IO端口复用的几种方式
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
IO端口复用
简介
I/O多路复用(multiplexing):本质是通过一种机制(系统内核缓冲I/O数据),让单个进程可以监视多个文件描述符,一旦某个描述符就绪(一般是读就绪或写就绪),能够通知程序进行相应的读写操作。
适用场景:高并发的服务器端。应对并发,常见的思维是创建多线程,每个线程管理一个并发操作,但是弊端很明显,就是多线程需要上下文切换,这个切换的消耗太大,当连接的客户端很多的时候弊端就很突出了。所示使用单线程的多路复用。
几种方式
1.s elect
Linux提供的select相关函数接口如下:
#include
#include
int select(int max_fd, fd_set *readset, fd_set *wri teset, fd_set *exceptset, struct timeval *timeout) FD_ZERO(int fd, fd_set* fds) /* 清空集合 */
FD_SET(int fd, fd_set* fds) /* 将给定的描述符加入集合 */
FD_ISSET(int fd, fd_set* fds) /* 将给定的描述符从文
件中删除 */
FD_CLR(int fd, fd_set* fds) /* 判断指定描述符是否
在集合中 */
接口解释:
1:select函数的返回值就绪描述符的数目,超时时返回0,出错返回-1。
2:第一个参数max_fd指待测试的fd个数,它的值是待测试的最大文件描述符
加1,文件描述符从0开始到max_fd-1都将被测试。
3:中间三个参数readset、writeset和exceptset指定要让内核测试读、写和异
常条件的fd集合,如果不需要测试的可以设置为NULL。
代码演示:
sockfd=socket(AF_INET,SOCK_STREAM,0);
memset(&addr,0,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_port=htons(2000);
addr.sin_addr.s_addr=IN ADDR_ANY;
bind(sockfd,(struct sockaddr*)&addr,sizeof(addr)); listen(sockfd,5);
fd_set rset;
int max = 0;
int fds[5];
for(int i=0;i<5;i++)
{
memset(&client,O,sizeof(client);
addrlen=sizeof(client);
fds[i]=accept(sockfd,(struct sockaddr*)
&client,&addrlen);
if(fds[i]>max)
max=fds[i];
}
while(1)
{
FD_ZERO(&rset);
for(int i=0;i<5;i++)
{
FD_SET(fds[i],&rset);
}
puts("round again");
select(max+1,&rset,NULL,NULL,NULL);
for(int i=0;i<5;i++)
{
if(FD_ISSET(fds[i],&rset))
{
memset(buffer,0,MAXBUF);
read(fds[i],buffer,MAXBUF);
puts(buffer);
}
}
}
这是一段使用select的端口复用的简单代码。代码定义一个监听5个客户端的select模型。
从代码中可以看出几个问题:
1:
FD_ZERO(&rset);
for(int i=0;i<5;i++)
{
FD_SET(fds[i],&rset);
}
每次while循环都要需要重复调用FD_ZERO进行清除,并在FD_SET加入句柄。2:for(int i=0;i<5;i++)
{
if(FD_ISSET(fds[i],&rset))
{
memset(buffer,0,MAXBUF);
read(fds[i],buffer,MAXBUF);
puts(buffer);
}
}
每次读取数据都需要遍历所有句柄,所以就有O(n)的消耗。
3:select模型设计时有最大的上线值1024,可在源码中查看到。想要更高的并发的话就需要采用多线程了。
4:执行select函数时,存在着用户态和内核态的切换,需要把句柄从内核态切换到用户态。数量少的时候感知不强烈,高并发的时候能有明显的感觉。
以上4点也就是select模型的缺点,总结如下:
1:有上限要求(1024),更多的话就需要多线程了;
2:FDSET不能重用,每次都需要FDZERO;
3:获取句柄需要从用户态拷贝成内核态,开销大;
4:获取消息的形式是遍历。需要循环获取。时间复杂度O(n)。
相交于传统的套接字select也存在其优点:
1:效率高。
2:跨平台性好,几乎支持所有平台。
2.poll
poll的机制与select类似,与select在本质上没有多大差别,管理多个描述符也是进行轮询,根据描述符的状态进行处理,但是poll没有最大文件描述符数量的限制。
#include
int poll(struct pollfd fds[], nfds_t nfds, int time