IO端口复用的几种方式

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 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

相关文档
最新文档