一、前言:
我们知道UDP服务器在实际生活中用的蛮多的。但是由于设计的原因,UDP服务器默认不支持多线程并发的,本文用以探讨UDP服务器并发的实现。
我们先看下TCP 服务器 和 UDP 服务器的编程模型的差异
我们可以看到,对于TCP 服务器来说,有一个新的客户端连接的时候,会产生一个新的socket用于和新客户端通信。
而对于UDP来说,服务器只有一个socket。所有的客户端都是通过同一个socket进行通信。
用下面这张图看更直观一点
对于TCP,每个客户端都有一个socket,因此我们可以创建线程去处理对应的socket。
那对于UDP呢,只有一个socket,那我们如何做到多线程并发呢?
二、随机端口方式
tftpd 程序采用的是随机端口的方式。也就是说如果有一个新的客户端过来,服务器会再随机绑定一个端口号,生成一个新的socket和客户端通信。流程大概就像下面这种图:
这种方式由于每个客户端有会有独立的端口号 和 socket。故而我们可以采用多线程的方式去处理。每个线程处理一个socket和端口。
但是这种方式有个弊端!
我们知道,端口号实际上是一个 16位二进制数字表示。而16位二进制数字的最大值是 65535 。也就是说这种方式的UDP并发服务器最多只能并发65535。
但实际上是做不到这么多的,因为有些端口号有其他用途,而且如果UDP服务器把所有端口号都占领了,那对于整个系统来说是一场灾难,因为没有多余的端口号可以用了。
所以这种方式只适用于小型的UDP并发服务器。
那还有其他更好的方式吗?
我们可以采用数据队列的方式去实现
三、数据队列方式
对于UDP服务器,我们先创建以下几个重要线程:
接收线程,这个接收线程只从socket中读取数据,然后筛选分发到对应的数据队列中,不对数据再进一步处理。例如客户端1 的数据,就只会发送到数据队列1,客户端2的数据只会发送到数据队列2. 如果是新的客户端,则创建新的队列。
监听线程,负责查询是否有新的数据队列(也就是说有没有新的客户端发数据过来,因为新的客户端发送的数据,会被放到一个新建的数据队列中去),如果有,取出数据队列,然后创建一个新的线程去处理这个新的数据队列。
数据处理线程,该线程由监听线程创建,用于从数据队列中拿出数据进行处理。
拓扑图如下:
这样的话,每个客户端有对应一个数据队列,每个数据队列都对应一个线程。故而可以做到多线程并发。
原理我们已经知道了,那代码怎么实现呢?
我们封装出几个跟上面的TCP相似的函数接口。使用这些接口,可以很简单写出一个UDP并发服务器。例如:
/* 主函数 */
int main(int argc, char *argv[])
{
/* 定义一个listen指针。该结构体是自己定义的 */
struct listen *_listen;
/* 初始化socket,这个初始化过程跟普通的UDP初始化 socket套接字一样 */
sockfd = init_socket();
/*
开始监听这个socket. 最大的连接数为10,也就是说最多只有10个客户端
封装好的一个函数,功能有点类似于 TCP协议中的 listen 函数
*/
server_listen(&sockfd, 10);
while(1)
{
/*
获得一个连接。类似于TCP的 accept 函数
需要注意的是,如果没有连接, server_accept 函数将进入休眠状态,直到有一个新的客户端数据
客户端只有在第一次发生数据过来的时候,才会创建一个新的 listen ,并唤醒 server_accept 函数
之后,这个客户端的所有数据都将发送到 这个新的 listen 的数据队列中。
所以。通过这个 listen ,我们可以创建一个进程,由该进程去处理这个客户端之后的请求
这里,listen 有点像 TCP 协议中的 accept 函数新建的 sockfd
*/
_listen = server_accept();
/*
虽然说 server_accept 会进入休眠,但是仍然会被其它信号唤醒,所以要做个判断
判断下是否为 NULL 。为 NULL 则说明没有新的连接
*/
if(_listen == NULL){
continue;
}
printf("new client \r\n");
/*
启动一个 listen_phread 线程,并且,由该线程去处理这个连接
类似于TCP 的fork
*/
listen_pthread(_listen, listen_phread);
}
}
更多详细的讲解可以看这边,免费试听。
5G物联网云平台智能家居项目30天搞定
第二章:物联网云平台搭建
04 服务器多线程并发
本文同步分享在 博客“连志安的博客”(CSDN)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。