高性能udp服务器 .net,UDP高性能并发服务器模型

一、前言:

我们知道UDP服务器在实际生活中用的蛮多的。但是由于设计的原因,UDP服务器默认不支持多线程并发的,本文用以探讨UDP服务器并发的实现。

我们先看下TCP 服务器 和 UDP 服务器的编程模型的差异

57bcf05b78d428be8f77ada7d767db2e.png

我们可以看到,对于TCP 服务器来说,有一个新的客户端连接的时候,会产生一个新的socket用于和新客户端通信。

而对于UDP来说,服务器只有一个socket。所有的客户端都是通过同一个socket进行通信。

6c09458fb1cc8c4c57356bc21ef22db6.png

用下面这张图看更直观一点

5e987b0d8b9744f2d6d79a829107953e.png

对于TCP,每个客户端都有一个socket,因此我们可以创建线程去处理对应的socket。

那对于UDP呢,只有一个socket,那我们如何做到多线程并发呢?

二、随机端口方式

tftpd 程序采用的是随机端口的方式。也就是说如果有一个新的客户端过来,服务器会再随机绑定一个端口号,生成一个新的socket和客户端通信。流程大概就像下面这种图:

23b732726e4544dd69dc8e6801d84207.png

这种方式由于每个客户端有会有独立的端口号 和 socket。故而我们可以采用多线程的方式去处理。每个线程处理一个socket和端口。

但是这种方式有个弊端!

我们知道,端口号实际上是一个 16位二进制数字表示。而16位二进制数字的最大值是 65535 。也就是说这种方式的UDP并发服务器最多只能并发65535。

但实际上是做不到这么多的,因为有些端口号有其他用途,而且如果UDP服务器把所有端口号都占领了,那对于整个系统来说是一场灾难,因为没有多余的端口号可以用了。

所以这种方式只适用于小型的UDP并发服务器。

那还有其他更好的方式吗?

我们可以采用数据队列的方式去实现

三、数据队列方式

对于UDP服务器,我们先创建以下几个重要线程:

接收线程,这个接收线程只从socket中读取数据,然后筛选分发到对应的数据队列中,不对数据再进一步处理。例如客户端1 的数据,就只会发送到数据队列1,客户端2的数据只会发送到数据队列2. 如果是新的客户端,则创建新的队列。

监听线程,负责查询是否有新的数据队列(也就是说有没有新的客户端发数据过来,因为新的客户端发送的数据,会被放到一个新建的数据队列中去),如果有,取出数据队列,然后创建一个新的线程去处理这个新的数据队列。

数据处理线程,该线程由监听线程创建,用于从数据队列中拿出数据进行处理。

拓扑图如下:

4600c2929da207dd9ea70a286aacbf7b.png

这样的话,每个客户端有对应一个数据队列,每个数据队列都对应一个线程。故而可以做到多线程并发。

原理我们已经知道了,那代码怎么实现呢?

我们封装出几个跟上面的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源创计划”,欢迎正在阅读的你也加入,一起分享。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值