UDP 客户端/服务器实战:多客户端并发测试、代码详解与运行现象分析
上节课我们已经完成了UDP 客户端和服务器的基础编写,可以通过socket编程实现最基本的网络通信。这节内容的重点,不是再重新堆概念,而是结合课堂测试现象,把程序跑起来、看清楚、理解透彻。课堂上一个很真实的问题是:客户端发得太快了,终端刷屏严重,不方便观察。所以这节博客会从这个细节出发,进一步分析:UDP 客户端程序该怎么优化便于调试为什么加一个sleep(1)就能更清楚地观察程序行为UDP 为什么说“天然支持并发”多个客户端同时和一个服务器通信时,服务器如何区分它们本文会给出完整代码、编译方式、运行结果,以及配套的图示说明。一、先回顾:UDP 通信模型UDP 是一种无连接、面向报文的传输协议。它的通信流程非常简单:服务器端流程socket() - bind() - recvfrom() - sendto() - close()客户端流程socket() - sendto() - recvfrom() - close()和 TCP 最大的不同在于:UDP 不需要建立连接不需要 listen / accept一个服务器 socket 就能同时接收多个客户端的数据二、图解:UDP 为什么天然支持并发先看一个简单的结构图。+-------------------+ | UDP Server | | 绑定端口 8989 | +-------------------+ / | \ / | \ / | \ +----------------+ +----------------+ +----------------+ | UDP Client A | | UDP Client B | | UDP Client C | | 端口: 49671 | | 端口: 33617 | | 端口: 52103 | +----------------+ +----------------+ +----------------+说明服务端只有一个端口,比如8989多个客户端各自拥有不同的临时端口客户端发送数据时,服务器通过recvfrom()得到对方的 IP 和端口服务端再通过sendto()把响应回给对应客户端所以 UDP 的“并发”并不是像 TCP 那样靠accept()返回多个连接描述符实现的,而是:同一个 socket 反复接收来自不同客户端地址的数据包。这就是课堂上说的:UDP 天然支持一对多通信,不需要额外做连接管理。三、为什么要给客户端加sleep(1)如果客户端在while(1)循环里不断发送,CPU 会飞快地执行:while(1){sendto(...);recvfrom(...);}这样会出现两个问题:终端刷屏太快,看不清现象不方便观察多个客户端交替发送时的效果因此课堂上建议在客户端循环末尾加上:sleep(1);这样客户端每秒发送一次,现象就会非常清晰。四、完整代码示例下面我们给出一套可以直接运行的代码:udp_server.c:UDP 服务器udp_client.c:UDP 客户端功能说明:客户端周期性发送"hello, world, N"服务器收到后打印客户端 IP 和端口然后把消息原样回给客户端多开几个客户端,就能观察 UDP 一对多通信五、服务器代码:udp_server.c#includestdio.h#includestdlib.h#includestring.h#includeunistd.h#includearpa/inet.h#defineSERVER_PORT8989#defineBUF_SIZE1024intmain(){intfd=socket(AF_INET,SOCK_DGRAM,0);if(fd==-1){perror("socket");exit(1);}structsockaddr_inserv_addr;memset(serv_addr,0,sizeof(serv_addr));serv_addr.sin_family=AF_INET;