转载前注明出处,欢迎转载分享
如果一堆的client.c与server.c进行连接的话一定会产生很多的进程,也就是说每当来一个客户端请求,就会产生一个进程来服务,然而进程不可能无限制的产生,所以为了解决一对一占用资源的连接方式,引入了IO复用。
即:一个进程可以同时对多个客户请求进行服务。
I/O复用的适用如下:
- 当客户处理多个文件句柄时必须使用。
- 当一个客户同时处理多个套接口时,而这种情况是可能的,但很少出现。
- 如果一个TCP服务器既要处理监听套接口,又要处理已连接的套接口,一般也要用到I/O复用。
- 如果一个服务器既要处理TCP,又要处理UDP,一般要使用I/O复用。
- 如果一个服务器要处理多个服务或多个协议,一般要使用I/O复用。
总结:实际上,当一个接收端需要接收来自多个不同发送端的数据时,我们一般要用到I/O复用。
I/O复用的优点:
与多进程多线程技术相比,I/O多路复用技术的最大优势是系统开销小,系统不必创建进程、线程,也不必维护这些进程、线程,从而大大减小了系统的开销。
在与POSIX标准兼容的平台上,我们可以使用select函数实现I/O端口的复用,传递给select函数的参数会告诉内核:
- 我们所关心的文件描述符
- 对每个描述符,我们所关心的状态。(我们是要想从一个文件描述符中读或者写,还是关注一个描述符中是否出现异常)
- 我们要等待多长时间。(我们可以等待无限长的时间,等待固定的一段时间,或者根本就不等待)
从 select函数返回后,内核告诉我们以下信息:
- 对我们的要求已经做好准备的描述符的个数
- 对于三种条件哪些描述符已经做好准备。(读,写,异常)
有了这些返回信息,我们可以调用合适的I/O函数(通常是 read 或 write),并且这些函数不会再阻塞.
select函数
1
2 3 4 |
#include #include int |
返回值:
若有就绪描述符则为其数目,若超时则为0,若出错则为-1。
参数:
参数int maxfdp1代表的是文件描述符的数量+1,文件描述符是由0开始取的。
fd_set *readset,fd_set *writeset,fd_set*exceptset为select函数监视的三类文件描述符,调用select函数会阻塞,直到有描述符就绪(有数据可读,可写,或者有except)
最后一个参数,它指明我们要等待的时间:
1
2 3 4 5 |
struct { } |
有三种情况:
注意:当在100秒完成时而你指定200秒,则如果在100秒完成,就结束
对于fd_set类型的变量我们所能做的就是声明一个变量,然后为变量赋一个同种类型变量的值,或者使用一下几个宏来控制它:
1
2 3 4 5 |
#include int int int int |
select函数模型主要建立在fd_set类型的基础上,
fd_set是一组文件描述符的集合,在UNIX系统上通常会在头文件<sys/select.h>中定义常量FD_SETSIZE,即fd_set类型的大小,其值通常在1024合理,这样就能表示小于1024个的fd集合。
< sys/select.h>所在目录为:/usr/include/sys
我的centos6.8测出的原本大小为128字节,如图:
其中FD_ZERO宏将一个fd_set类型的所有位都置为0,对于select函数中间的三个参数,除了我们所感兴趣的条件外,其他的都可以是空指针,如果三个参数都被设置为空(NULL),
这样我们就获得了一个比sleep更精确的计时器。
使用宏进行如下操作时:
1
2 3 4 5 6 7 8 |
fd_set FD_ZERO(&readset); FD_ZERO(&writeset); FD_SET(0, FD_SET(3, FD_SET(1, FD_SET(2, select(4, |
效果如图:
select函数的优点和缺点:
优点:
- select函数可以处理多个socket描述符。
- select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点。
- select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024(软上限),可以通过修改宏定义甚至重新编译内核的方式提升这一限制,但是这样也会造成效率的降低,也就是说1024个描述符的集合数量大小刚刚好。
什么是软上限?什么是硬上限?
软上限:一定要达到的目标,超过就不划算而已。
硬上限:超过就毫无价值。
缺点:
- select调用,要遍历内核中就绪的描述符集合,内核把东西拷贝给用户,用户还要遍历一遍描述符集合。
- select调用,要将用户态的描述符集合拷贝到内核态,再将内核态数据拷贝到用户态。
参考资料:
https://segmentfault.com/a/1190000003063859(LinuxIO模式及select.poll.epoll分析)(推荐阅读)