全双工通信、面向无连接、不可靠
UDP(User Datagram Protocol)用户数据报协议,是不可靠的无连接的协议。在数据发送前,因为不需要进行连接,所以可以进行高效率的数据传输。
适用场景
发送小尺寸数据(如对DNS服务器进行IP地址查询时)
适合于广播/组播式通信中。
MSN/QQ/Skype等即时通讯软件的点对点文本通讯以及音视频通讯通常采用UDP协议

服务器:
1. 创建数据报套接字 socket
2. 填充网络信息
3. 绑定 bind
4. 发送接收消息 sendto/recvfrom
5. 关闭套接字 close
客户端:
1. 创建数据报套接字 socket
2. 指定网络(服务器)信息
3. 发送接收消息 sendto/recvfrom
4. 关闭套接字 close
要求:客户端向服务器发送消息,然后服务器向客户端回发一条一样的消息
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- #define N 128 // 宏定义数组大小
-
- // 服务器:
- // 1. 创建数据报套接字 socket
- // 2. 填充网络信息
- // 3. 绑定 bind
- // 4. 发送接收消息 sendto/recvfrom
- // 5. 关闭套接字 close
-
- int main(int argc, char const *argv[])
- {
-
- // 1. 创建数据报套接字 socket
- int serverfd = socket(AF_INET, SOCK_DGRAM, 0);
- if (serverfd < 0)
- {
- perror("serverfd socket err");
- return -1;
- }
- printf("socket scuess\n");
-
- // 2. 填充网络信息
- struct sockaddr_in myaddr; // 服务器结构体变量
- myaddr.sin_family = AF_INET; // IPV4协议
- // 结构体成员变量是sin_addr ,sin_addr是struct in_addr 结构体类型的,成员变量为 s_addr,
- // 网络ip地址需要转成机器识别的类型;
- myaddr.sin_addr.s_addr = INADDR_ANY;
- // 端口
- myaddr.sin_port = htons(atoi(argv[1]));
-
- // 3. 绑定 bind
- // 绑定自己的地址
- // 需要强转成通用结构体类型的地址
- socklen_t addrlen = sizeof(myaddr);
- if (bind(serverfd, (struct sockaddr *)&myaddr, addrlen) < 0)
- {
- perror("bind err");
- return -1;
- }
- printf("bind scuess\n");
-
- // 4. 发送接收消息 sendto/recvfrom
- ssize_t len = -1; // 接收recv返回值
- char buf[N] = "";
- struct sockaddr_in cliaddr; // 存放客户端结构体变量
-
- while (1)
- {
- // 接收来自客户端的消息
- // 清空数组
- memset(buf, 0, N);
- // recvfrom最后两个参数为发送端的网络地址信息
- len = recvfrom(serverfd, buf, N, 0,
- (struct sockaddr *)&cliaddr, &addrlen);
- if (len < 0)
- {
- perror("recv err");
- break;
- }
-
- // 接收到quit时退出
- if (buf[strlen(buf) - 1] == '\n')
- {
- buf[strlen(buf) - 1] = '\0';
- }
- if (strcmp(buf, "quit") == 0)
- {
- break;
- }
-
- // 服务器获取的ip地址与端口号都是网络字节序,输出的的时候需要转成主机字节序
- printf("ip = %s, port = %d\n", inet_ntoa(cliaddr.sin_addr),
- ntohs(cliaddr.sin_port));
- printf("recv data = %s\n", buf);
-
- // 向客户端回发消息
- // sendto最后两个参数为接收端的网络地址信息
- len = sendto(serverfd, buf, len, 0,
- (struct sockaddr *)&cliaddr, sizeof(cliaddr));
- if (len < 0)
- {
- printf("send error\n");
- return -1;
- }
- }
-
- close(serverfd);
-
- return 0;
- }
-
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- #define N 128 // 宏定义数组大小
-
- // 客户端:
- // 1. 创建数据报套接字 socket
- // 2. 指定网络(服务器)信息
- // 3. 发送接收消息 sendto/recvfrom
- // 4. 关闭套接字 close
-
- int main(int argc, char const *argv[])
- {
-
- // 1. 创建数据报套接字 socket
- int clientfd = socket(AF_INET, SOCK_DGRAM, 0);
- if (clientfd < 0)
- {
- perror("serverfd socket err");
- return -1;
- }
-
- // 2. 指定网络(服务器)信息
- struct sockaddr_in server_addr; // 服务器结构体变量
- server_addr.sin_family = AF_INET; // IPV4协议
- // 结构体成员变量是sin_addr ,sin_addr是struct in_addr 结构体类型的,成员变量为 s_addr,
- // 网络ip地址需要转成机器识别的类型;
- server_addr.sin_addr.s_addr = inet_addr(argv[1]);
- // 端口
- server_addr.sin_port = htons(atoi(argv[2]));
- // 结构体大小
- socklen_t addrlen = sizeof(server_addr);
- // 3. 发送接收消息 sendto/recvfrom
- ssize_t len = -1; // 接收send返回值
- char buf[N] = "";
- char buff[N] = "";
-
- while (1)
- {
- // 向服务器端发送消息
- // 清空数组
- memset(buf, 0, N);
-
- // 从终端读取内容
- len = read(1, buf, N);
- if (buf[strlen(buf) - 1] == '\n')
- {
- buf[strlen(buf) - 1] = '\0';
- }
-
- // sendto最后两个参数为接收端的网络地址信息
- len = sendto(clientfd, buf, len, 0,
- (struct sockaddr *)&server_addr, addrlen);
- if (len < 0)
- {
- printf("send error\n");
- return -1;
- }
-
- if (strcmp(buf, "quit") == 0)
- {
- break;
- }
-
- // 接收服务器端回发的消息
- // 清空数组
- memset(buf, 0, N);
- // recvfrom最后两个参数为发送端的网络地址信息
- len = recvfrom(clientfd, buf, N, 0,
- (struct sockaddr *)&server_addr, &addrlen);
- if (len < 0)
- {
- perror("recv err");
- break;
- }
- // 格式化输出
- printf("recv:%s!!!!\n", buf);
-
- fprintf(stdout, "recv:%s!!!!", buf);
-
- sprintf(buff, "recv:%s!!!!", buf);
- printf("%s\n", buff);
- }
-
- close(clientfd);
-
- return 0;
- }
-
服务器端

客户端
