您的位置:首页 > 理论基础 > 计算机网络

网络编程学习:io模型之io多路复用

2017-11-09 15:25 645 查看

多路复用的概念:

简而言之,就是将准备要用的文件描述符添加到一张表里,然后让select等待表里的任一描述符准备就绪(就是可以执行了),然后执行那个已经准备就绪的文件描述符,然后把其他的没有准备好的文件描述符全都删除;

援引知乎上的一个解释:

这些名词比较绕口,理解涵义就好。一个epoll场景:一个酒吧服务员(一个线程),前面趴了一群醉汉,突然一个吼一声“倒酒”(事件),你小跑过去给他倒一杯,然后随他去吧,突然又一个要倒酒,你又过去倒上,就这样一个服务员服务好多人,有时没人喝酒,服务员处于空闲状态,可以干点别的玩玩手机。至于epoll与select,poll的区别在于后两者的场景中醉汉不说话,你要挨个问要不要酒,没时间玩手机了。io多路复用大概就是指这几个醉汉共用一个服务员。

作者:匿名用户链接:https://www.zhihu.com/question/32163005/answer/55687802

来源:知乎

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

io多路复用函数

int select(int maxfdpl, fd_set *readset, fd_set *writeset, fd_set exceptset, const struct timeval *timeout);

功能:允许一个进程去操作多个文件描述符,阻塞等待一个或多个文件描述符就绪,当有一个或者多个文件描述符准备就绪,则函数立即返回;

参数:

maxfdpl:指定待测试的描述符个数,它的值是描述符集合中最大值加1(因为描述符是从0开始的,例如:集合里有{0,1,2,3,4},此时描述符的个数为5(即最大值4加1));

readset:读文件描述符集合;

writeset:写文件描述法集合;

exceptset:异常条件的描述符集合;

timeout:它告知内核等待所指定的描述符中的任何一个多长时间,即用作超时检测;

返回值:

成功:

如果timeout == NULL,则返回准备就绪的文件描述的个数;

如果timeout != NULL,超时后返回0;

失败:

返回-1;

多路复用实例(让标准输入和accept同时可以被操作)

服务器端
#include "select.h"

int main(int argc, const char *argv[])
{
int listenfd, connfd;
struct sockaddr_in servaddr, cl
4000
iaddr;
socklen_t addrlen = sizeof(struct sockaddr_in);
char buf
;

if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
errlog("socket error");
}

servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(atoi(argv[2]));

if(inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
{
errlog("inet_pton error");
}

if(bind(listenfd, (struct sockaddr *)&servaddr, addrlen) < 0)
{
errlog("bind error");
}

if(listen(listenfd, LISTENQ) < 0)
{
errlog("listen error");
}

int maxfd;
fd_set readfds, middlefds;

//清空集合
FD_ZERO(&readfds);

maxfd = listenfd;

while(1)
{
//将标准输入和接收客户端连接加入到集合中
FD_SET(0, &readfds);
FD_SET(listenfd, &readfds);

//阻塞检测&readfds中哪个文件描述符准备好了,如果准备好了,就不再阻塞给下边的代码放行,同时清空那些没有准备好的文件描述符;
if(select(maxfd + 1, &readfds, NULL, NULL, NULL) < 0)
{
errlog("select error");
}

//检测readfds集合中0号文件描述符准备好了没有,准备好了的话则返回1;
if(FD_ISSET(0, &readfds))
{
fgets(buf, N, stdin);
fputs(buf, stdout);
}

if(FD_ISSET(listenfd, &readfds))
{
if( (connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &addrlen)) < 0)
{
errlog("accept error");
}

printf("%s--%d is coming\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
}
}

close(listenfd);
close(connfd);

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: