参考链接:基于UDP的服务器端和客户端_C语言中文网
一、IP地址 、端口、通信协议
1、IP地址
网络中的计算机使用IP地址来进行唯一标识。
2、端口号
端口号是计算机中的应用程序的一个整数数字标号,用来区分不同的应用程序。
0~1024为系统使用的保留端口号;
0~65535为有效端口号;
1024~65535自定义端口号时能够使用的范围。
3、通信协议
通信协议就是网络通信中的规则,分为TCP和UDP两种协议。
第一种:TCP协议
中文名:TCP(控制传输协议)
协议说明:TCP是面向连接的,可靠的、基于字节流的传输层通信协议
举例:类似于打电话,双方都接通才能进行对话
特点:虽然效率低,但是数据传输安全。
第二种:UDP协议
中文名:UDP(数据报协议)
协议说明:UDP是一种面向无连接的传输层通信协议
举例:类似于发短信,不需要双方建立连接,但是传输数据较小,数据报的大小限制在 64K以内。
特点:效率比较高,但是数据传输不安全,容易丢包。
二、网络编程三要素
IP地址不同
端口号相同
协议相同
三、UDP编程
UDP使用数据报进行数据传输。
没有客户端与服务器端之分,只有发送方与接收方。
两者先启动任何一方都不会报错,但是会出现数据丢包现象。
且发送的内容大小必须在64K以内。
自我实践:
开发工具:QtCreate
实践内容:基于UDP的回声服务器端/客户端
1、项目目录:
2、服务器端代码
//输入输出头文件
#include <stdio.h>
//socket头文件
#include <winsock2.h>
//ws2_32.lib库
#pragma comment(lib, "ws2_32.lib")
// !定义buf大小
#define BUFF_SIZE 100
//main函数入口
int main()
{
// 初始化dll库
// 1.定义结构
WSADATA wsaData;
// 2.设置socket版本和存储结构体
WSAStartup(MAKEWORD(2,2), &wsaData);
//创建套接字
SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
// 定义套接字结构体
sockaddr_in servAddr;
// 将所有字节赋值为0
memset(&servAddr, 0, sizeof (servAddr));
// 设置协议
servAddr.sin_family = PF_INET;
// 设置IP地址
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
// 设置端口
servAddr.sin_port = htons(1234);
// 绑定套接口信息
bind(sock, (SOCKADDR*)&servAddr, sizeof (SOCKADDR));
// 接收客户端消息
// 1.获取客户端IP地址信息
SOCKADDR clntAddr;
// 2.定义缓冲区大小
int nSize = sizeof (SOCKADDR);
char buffer_c[BUFF_SIZE] = {0};
while(1)
{
char buffer_s[BUFF_SIZE] = {0};
//给客户端发送消息
printf("server:");
gets(buffer_s);
// 将消息发送给客户端
//sock,缓冲区地址,数据长度,可选参数,客户端地址,客户端大小
sendto(sock, buffer_s, strlen(buffer_s), 0, &clntAddr, nSize);
// 3.接收客户端消息数据
int strLen = recvfrom(sock, buffer_c, BUFF_SIZE, 0, &clntAddr, &nSize);
buffer_c[strLen] = 0;
printf("Message from client: %s\n", buffer_c);
}
//关闭socket套接字
closesocket(sock);
//关闭socket套接字绑定和接触socket套接字所占用资源
WSACleanup();
return 0;
}
3、客户端代码
//输入输出头文件
#include <stdio.h>
//sock头文件
#include <winsock2.h>
//添加lib库
#pragma comment(lib, "ws2_32.lib")
//宏定义BUFF大小
#define BUFF_SIZE 100
//主函数程序入口
int main()
{
//初始化DLl
WSADATA wsaData;
//绑定sock版本和存储地址
WSAStartup(MAKEWORD(2, 2), &wsaData);
//创建套接字
SOCKET sock = socket(PF_INET, SOCK_DGRAM, 0);
//定义套接字内容
sockaddr_in sockadd;
//将所有字节定义为0
memset(&sockadd, 0, sizeof (sockadd));
//定义协议
sockadd.sin_family = PF_INET;
//定义IP地址
sockadd.sin_addr.s_addr = inet_addr("127.0.0.1");
//定义端口
sockadd.sin_port = htons(1234);
//绑定套接字
//发送消息给服务器
//1.创建一个服务器套接字
sockaddr fromAddr;
int addlen = sizeof (fromAddr);
char buffer_s[BUFF_SIZE];
//接收服务器回传的消息
while (1) {
//client输入消息buffer
char buffer_c[BUFF_SIZE] = {0};
printf("client:");
gets(buffer_c);
sendto(sock, buffer_c, strlen(buffer_c), 0,
(struct sockaddr*)&sockadd, sizeof (sockadd));
//接收server数据信息
int strLen = recvfrom(sock, buffer_s, BUFF_SIZE, 0,
&fromAddr, &addlen);
buffer_s[strLen] = 0;
printf("Message from server :%s\n", buffer_s);
}
//关闭套接字
closesocket(sock);
//接触套接字绑定和套接字资源占用
WSACleanup();
return 0;
}
4、运行结果
5、pro文件
LIBS += -lWs2_32
6、一点问题
这个代码存在一点小问题,代码是在开头链接里的客户端回传代码中的基础上,做了修改。然后勉强实现了双向通信,但是通信过程不流畅。