Linux单线程并发服务器探索

2018-04-18 11:05刘俊汐
数字通信世界 2018年1期
关键词:描述符服务器端监听

刘俊汐,张 文

(1.绵阳中学,绵阳 621000;2.电子科技大学计算机科学与工程学院,成都 611731)

1 引言

大部分的并发服务器采用fork子进程方式,从而达到并发的效果,本文将探索另一种并发服务器的设计思想,仅使用单线程,就可以完成并发功能。文中重点讲述如何设计一个单线程并发服务器,需要怎样的线程结构,以及select函数在单线程中如何管理众多的套接字描述符。通过实验结果的分析,再次强化对select函数的理解,了解套接字描述符的变化过程。

2 基础理论

文件描述符是由内核创建的文件的索引,指向被打开的文件,涉及I/O的系统调用都会使用文件描述符。而每个活动的套接字由一个小整数标识,被称为套接字描述符。由于套接字描述符也存放在文件描述符表中,所以同一进程不能拥有相同数值的文件描述符和套接字描述符。

Select函数的原型如下:Int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,st ruct t imeval *t imeout)。主要讲述readrfds和timeout参数。readfds指向可读文件描述符集,如果其中某个文件可读,select的返回值大于0。若没有处于可读状态的文件,再根据timeout判断是否超时,如果超时,select返回0;若select返回负值,说明出错。如果不关心任何文件的读变化可以将readfds指向NULL。writefds、er rorfds与readfds 类似,都是指向文件描述符集。

timeout指向一个超时时间结构体,通过它控制select的执行状态,若指向NULL,select将以阻塞方式执行,直到事件发生才返回;若将时间值设为0,将select变为一个非阻塞函数,立刻返回结果;若timeout值大于0,select仅在timeout时间段内阻塞,若事件出现或时钟超时将返回。

3 设计一个单线程并发服务器

单线程服务器中,所有的套接字都由一个线程管理。试想一个单线程服务器,有许多客户连接到该服务器上。线程以阻塞方式等待数据的到达,一旦任何一个连接上有数据到达,线程将被唤醒,并处理请求和发送响应。然后它将再次阻塞,等待其他连接上的数据到达。只要CPU足够快地应付服务器上出现的工作负荷,使用单线程就能像使用多线程那样处理各个请求。

只通过单线程管理所有的套接字,需要使用基础理论部分提到的select函数。当有新的连接或读写I/O准备就绪,内核会自动修改文件描述符集的值。通过将监听套接字和连接套接字都放入select 函数的可读文件描述符集中,一旦有新的连接请求或读I/O准备就绪,内核会将对应的套接字描述符置为1,借助FD_ISSET宏函数来确定具体发生的事件。所以在程序中,只要能找到发生变化的套接字描述符,即可以进行相应的操作。

4 单线程并发ECHO服务器设计

在客户端,首先创建一个套接字,通过该套接字与服务器建立连接,在该套接字上不断完成写读操作。如果客户端完成请求,则可以断开与服务器的连接,释放资源。

在服务器端,首先创建监听套接字,将监听套接字放入文件描述符集,通过调用select函数,由内核修改可读文件描述符集对应位的值,然后判断是监听套接字就绪还是连接套接字上的读I/O就绪,若监听套接字就绪,则进行连接,并将该套接字描述符加入到活跃文件描述符集afds中;如果连接套接字上的读I/O就绪,则进行数据处理,如图1所示。

每当监听套接字就绪时,即服务器每连接一个客户端,调用accept函数返回一个连接套接字ssock,并将其放入afds活动文件描述符集中。若可读文件描述符集中有就绪I/O时,并且文件描述符不是监听套接字msock,便调用echo()函数进行回射处理。如果客户端结束服务,将其从对应的afds中删除。

图1 服务器端流程图

5 实验结果

首先运行服务器端程序。其套接字描述符的打印值如下,监听套接字为23,最大可用的套接字描述符数量为1024个。看到afds中第24位被置为1,由于仅使用几个客户端测试,所以后面的描述符省略不打印。此时服务器程序阻塞于select函数。msock is:23。

接着打开一个客户端,不发送数据。从打印信息显示此时有一个连接套接字ssock25建立。由于此时有一个客户端建立连接,内核修改r fds的状态,将第24位置为1,表明监听套接字就绪,select 函数得以返回。活动描述符集afds中第24、26被置为1,表示一个监听套接字和一个连接套接字。rfds is:

在客户端窗口中输入数据sdads,可以看到接收框中显示相同的数据。因为此时连接套接字25上的网络I/O就绪,所以select将rfds的第26位被置为1并返回,活动描述符集afds没有变化。

图2 第一个客户端发送数据

此时打开第二个客户端,不发送数据,可以看到显示连接套接字ssock26,此时rfds的第24位被置为1,表明监听套接字就绪。因为有了新的连接,所以afds中第27位被置为1。

现在关闭第一个客户端,看到rfds的第26位被置1,afds中将25连接套接字对应位删除,只有一个连接套接字(26)和一个监听套接字活跃。

当关闭第二个客户端时,看到rfds的第27位被置1,afds中将26连接套接字对应位删除,现在只有一个监听套接字活跃。

6 结束语

由于ECHO服务器属于数据到达驱动,所以能够使用单线程服务器完成多线程服务器的功能。关键是使用了操作系统的异步I/O函数select,通过select管理服务器上所有的套接字描述符,由于函数返回时内核会修改套接字描述符集,所以能够知道有新的连接请求或I/O就绪。

[1] Douglas E.Comer,David L.Stevens.用TCP/IP进行网际互连ü客户-服务器编程与应用[M].北京∶电子工业出版社,2008.

[2] W.Richard Stevens,Bill Fenner,Andrew M.Rudoff.UNIX 网络编程 卷 1 :套接字网络编程API.第3版[M].北京∶人民邮电出版社,2015.

猜你喜欢
描述符服务器端监听
基于结构信息的异源遥感图像局部特征描述符研究
英国风真无线监听耳机新贵 Cambridge Audio(剑桥)Melomania Touch
Linux环境下基于Socket的数据传输软件设计
千元监听风格Hi-Fi箱新选择 Summer audio A-401
基于AKAZE的BOLD掩码描述符的匹配算法的研究
基于深度学习的局部描述符
网络监听的防范措施
基于Qt的安全即时通讯软件服务器端设计
基于Qt的网络聊天软件服务器端设计
特征联合和旋转不变空间分割联合的局部图像描述符