一. 关于poll

对于IO复用模型,其优点无疑是免去了对一个个IO事件就绪的等待,转而代之的是同时对多个IO数据的检测,当检测等待的事件中至少有一个就绪的时候,就会返回告诉用户进程“已经有数据准备好了,快看看是哪个赶紧处理”,而对于IO复用的实现,除了可以用select函数,另外一个函数仍然支持这种复用IO模型,就是poll函数;


二. poll函数的用法

虽然同样是对多个IO事件进行检测等待,但poll和select多少还是有些不同的:

函数参数中,

先来说nfds,这个是指当前需要关心的文件描述符的个数;

timeout同样是设置超时时间,只是和select的timeout是一个结构体不一样,这里只是一个整型类型,且含义是毫秒

fds是一个结构体指针,如下:

结构体中,

fd表示所要关心的文件描述符;

events表示该文件描述符所关心的事件,这是一个输入型参数,要告诉操作系统这个文件描述符对应的事件所关心的操作事件是什么,比如读或写;

revents是一个输出型参数,表示当poll返回时告诉用户什么操作事件是就绪的,比如如果POLLIN是就绪的,那么返回时revent的值就是POLLIN,告诉用户fd事件的POLLIN是就绪的;

events和revents的值可以为如下:

选项其实不止这三个,只是这里的讨论中这三个选项是最常用的;

events设置为POLLIN表示fd所需要读取数据,而revents若返回POLLIN则表示data已经ready可以读取了;

同样,events设置为POLLOUT表示fd所关心数据的写入,而revents返回POLLOUT则表示写事件就绪可以进行数据的写入;

至于POLLPRI,后面的解释是作为紧急选项来设置的,在TCP协议报文中有个URG的紧急指针是表示先从紧急数据的地方开始读取,这里也是这个意思;


与select不同的是,reads与writes是输入输出参数,我上一篇博客中设置中:

 else if(fds[i] > 0 &&\FD_ISSET(fds[i],&reads))    //正常事件,但是是非监听时间,也就代表时新建立的new_sock。{//  char buf[1024];ssize_t s = read(fds[i],buf,sizeof(buf) -1);if(s > 0){buf[s] = '\0';//  printf("client : %s\n",buf);printf("client : %s",buf);FD_SET(fds[i],&writes);//  write(fds[i],buf,sizeof(s)+1);}else if(s == 0){printf("client quit...\n");close(fds[i]);fds[i] = -1;}else{}}else{}if(fds[i] > 0&&\FD_ISSET(fds[i],&writes)){write(fds[i],buf,sizeof(buf));}

在获取读事件时对将fds[i],设置到写事件中,而在poll中,读事件判断中修改设置为写事件。需要等待下一次循环,才能够获取到写事件,然后还必须将events属性在设置回来。

poll与select不同在于描述符存储方式不同和参数类型不同。

1.结构体数组的管理:当每次有需要关心的描述符时,将其放入结构体中,每次有无效的描述符后,将其描述符置-1,下次poll函数会忽略它。当有新的描述符加入时,从头遍历结构体,将为-1的元素设为要关心的描述符事件状态。切记:当新的描述符加到结构体数组末尾时要更新关心描述符个数,即poll第二个参数。

2.每次调用poll后,结构体元素revents会存储就绪事件状态,当每次重新调用poll之前时,系统会自己设置其为0,重新监听关心事件(不需要用户重新置0)

3.poll中参数不是输入,输出型,因此timeout,struct pollfd *fds参数不需重置,nfds看情况(参照第一点),而select函数是输入输出类型,每次调用前需重置。

下面看服务端的代码,客户端就不写了:

#include<poll.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<errno.h>
#include<netinet/in.h>
#include<arpa/inet.h>#define _BACKLOG_ 5
#define _SIZE_ 64static void usage (const char *proc)
{printf("%s [ip][prot]\n",proc);
}static int start(char *ip,int port)
{int sock = socket(AF_INET,SOCK_STREAM,0);if(sock < 0){perror("socket");exit(1);}int opt = 1;if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)) < 0){perror("setsockopt");exit(3);}struct sockaddr_in local;local.sin_family = AF_INET;local.sin_port = htons(port);local.sin_addr.s_addr = inet_addr(ip);if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0){perror("bind");exit(2);}if(listen(sock,_BACKLOG_) < 0){perror("listen");exit(2);}return sock;
}int main(int argc,char* argv[])
{if(argc != 3){usage(argv[0]);return 1;}int port = atoi(argv[2]);char *ip = argv[1];int listen_sock = start(ip,port);//pollfd arraysstruct pollfd polls[_SIZE_];int index = 0;int timeout = 5000; //check question timeint i = 0;polls[0].fd = listen_sock;polls[0].events = POLLIN;polls[0].revents = 0;++index;//init polls.fdfor(i = 1;i < _SIZE_;++i){polls[i].fd = -1;}char buf [1024];ssize_t s = 0;struct sockaddr_in client;socklen_t len = sizeof(client);int done = 0;int max_fd = 1;while(!done){switch(poll(polls,max_fd,timeout)){case -1:perror("poll");break;case 0:printf("timeout\n");break;default:{size_t i = 0;for(;i<_SIZE_;++i){if((polls[i].fd == listen_sock) && (polls[i].revents == POLLIN)){int accept_sock = accept(listen_sock,(struct sockaddr*)&client,&len);if(accept_sock < 0){perror("accept");continue;}printf("connet success\n");for(;i < _SIZE_;++i){if(polls[i].fd == -1){polls[i].fd = accept_sock;polls[i].events = POLLIN;++max_fd;break;}}if(i == _SIZE_){close(accept_sock);}}else if((polls[i].fd > 0) &&(polls[i].revents == POLLIN) ){ssize_t size = read(polls[i].fd,buf,sizeof(buf)-1);if(size < 0){perror("read");continue;}else if(size == 0){printf("client close \n");struct pollfd tmp = polls[i];polls[i] = polls[max_fd -1];polls[max_fd -1] = tmp;close(polls[max_fd - 1].fd);polls[max_fd - 1].fd = -1;}else{buf[size] = '\0';printf("client # %s",buf);polls[i].events = POLLOUT;}}else if(polls[i].fd > 0&& \polls[i].revents == POLLOUT){write(polls[i].fd,buf,sizeof(buf));polls[i].events = POLLIN;}}}break;}}return 0;
}

运行结果:

ok

转载于:https://blog.51cto.com/memory73/1784093

socket编程:多路复用I/O服务端客户端之poll相关推荐

  1. Netty的Socket编程详解-搭建服务端与客户端并进行数据传输

    场景 Netty在IDEA中搭建HelloWorld服务端并对Netty执行流程与重要组件进行介绍: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article ...

  2. c# WINFORM SOCKET编程-简单聊天程序(服务端)

    初学C#的SOCKET编程,照着网上的代码写下来,程序总是有问题,经过自己长时间的调试,完成程序,以下是原码,有需要可以参考一下,还不完善,欢迎大家批评指正.(这里的代码没更新,附件重新上传更新,在另 ...

  3. Socket编程实践(6) --TCP服务端注意事项

    僵尸进程处理 1)通过忽略SIGCHLD信号,避免僵尸进程 在server端代码中添加 signal(SIGCHLD, SIG_IGN); 2)通过wait/waitpid方法,解决僵尸进程 sign ...

  4. TCP/IP网络编程之基于TCP的服务端/客户端(二)

    回声客户端问题 上一章TCP/IP网络编程之基于TCP的服务端/客户端(一)中,我们解释了回声客户端所存在的问题,那么单单是客户端的问题,服务端没有任何问题?是的,服务端没有问题,现在先让我们回顾下服 ...

  5. TCP/IP网络编程之基于TCP的服务端/客户端(一)

    TCP/IP网络编程之基于TCP的服务端/客户端(一) 理解TCP和UDP 根据数据传输方式的不同,基于网络协议的套接字一般分为TCP套接字和UDP套接字.因为TCP套接字是面向连接的,因此又称为基于 ...

  6. 二、Netty服务端/客户端启动整体流程

    一.综述 Netty 的整体流程相对来说还是比较复杂的,初学者往往会被绕晕.所以这里总结了一下整体的流程,从而对 Netty 的整体服务流程有一个大致的了解.从功能上,流程可以分为服务启动.建立连接. ...

  7. 一个简单的完成端口(服务端/客户端)类

    一个简单的完成端口(服务端/客户端)类 作者:spinoza 翻译:麦子芽儿, POWERCPP(后面部分内容) 下载源代码 原文网址:http://www.codeproject.com/KB/IP ...

  8. linux 进程sockfd fork,Linux下多进程服务端客户端模型一(单进程与多进程模型)...

    本文将会简单介绍Linux下如何利用C库函数与系统调用编写一个完整的.初级可用的C-S模型. 一.基本模型: 1.1   首先服务器调用socket()函数建立一个套接字,然后bind()端口,开始l ...

  9. C# unity网络游戏实战泡泡堂(服务端+客户端整套源码)

    游戏采用unity引擎开发. 语言有C#(unity),C++做服务端构建,linux下的服务器搭建. 历经一年自主开发,使用帧同步方式进行网络链接构建,unity实现时间片的同步. 源码3W+行,工 ...

最新文章

  1. Google正式将网速列为网站排名因素
  2. NYOJ 541 最强的战斗力
  3. es6 --- Promise封装读取文件操作
  4. 前端学习(1377):express路由参数
  5. GitChat专栏:Spring Cloud 与 Consul 的整合使用
  6. 关于不过洋节的通知_平安夜、圣诞节安全教育告家长通知书
  7. 鹤岗一中2021年高考成绩查询,2021鹤岗市地区高考成绩排名查询,鹤岗市高考各高中成绩喜报榜单...
  8. docker安装ping命令
  9. Coinbase报告:DeFi协议总锁仓价值已超250亿美元,同比增长2500%
  10. [原创]linux简单之美(三)
  11. PyCharm中配置模板
  12. 在win 10系统下安装VS 2015
  13. D5从零开始学Flash游戏开发系列教程
  14. Gary Marcus再发万字长文,列14个QA回应机器学习批判言论
  15. 你绝对不知道 Vue 也有生老病死
  16. 【毕业设计】基于stm32的智能扫地机器人设计与实现 - 单片机 物联网
  17. 台式计算机识别不了鼠标,USB无线鼠标失灵电脑检测不到无法识别怎么办
  18. latex 参考文献显示问号_如何自学latex软件
  19. C语言itoa()函数
  20. 从 Arm Compiler 5 迁移到 Arm Compiler 6

热门文章

  1. .NET2.0隐形的翅膀,正则表达式搜魂者【月儿原创】
  2. ASP.net 2.0下应用程序离线信息
  3. 使用 mkdocs 搭建个人 wiki 站点
  4. 同步、异步、堵塞、非堵塞和函数调用及I/O之间的组合概念
  5. OpenCV实现在图像中写入汉字
  6. VC使用ActiveX控件常见问题
  7. Linux中bashrc河bash_profile
  8. php文件保存类库,PHP生成PDF文件类库大全[开源]
  9. 轻量级mysql服务_Navicat连接阿里云轻量级应用服务器mysql
  10. latex 中文_【小白向】LaTeX 中文入门