socket编程:多路复用I/O服务端客户端之poll
一. 关于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
相关文章:
【MATLAB】符号数学计算(八):符号分析可视化
一、funtool分析界面 在命令行窗口中输入: funtool 这里就说一下第四排: Insert:把当前激活窗的函数写入列表Cycle:依次循环显示fxlist中的函数Delete:从fxlist列表中删除激活窗的函数Reset:使计算器恢复…

java 根据实体对象生成 增删改的SQL语句 ModelToSQL
2019独角兽企业重金招聘Python工程师标准>>> java 根据实体对象生成 增删改的SQL语句 ModelToSQL 转载于:https://my.oschina.net/miaojiangmin/blog/2907010

深入浅出SpringBoot源码分析
Spring源码非常多,不要迷失在源码的汪洋大海里,抓住主要脉络,有需要再研究即可。 Bean的初始化 1.发现所有的bean ComponentScanAnnotationParser.parse()调用doScan()扫包 这里只是扫用户定义的bean,系统的自然不用扫 ClassPathBeanDefinitionScanner.doScan protected…

HBase基本知识
为什么80%的码农都做不了架构师?>>> 概述 HBase 特性: 强一致性读写: HBase 不是 "最终一致性(eventually consistent)" 数据存储. 这让它很适合高速计数聚合类任务。自动分片(Automatic sharding): HBase 表通过region分布在集群…

【编程题】猜年龄
题目标题: 猜年龄 美国数学家维纳(N.Wiener) 智力早熟,11岁就上了大学。他曾在1935~1936年应邀来中国清华大学讲学。 一次,他参加某个重要会议,年轻的脸孔引人注目。于是有人询问他的年龄,他回答说: “我年龄的立方是个…

XenServer和VMware vSphere技术比较
此次将Citrix XenServer7.1和VMware ESXi 6.5从技术角度进行比较,并从企业角度对企业关心的项进行比较。主要包含市场地位、服务器虚拟化底层稳定性、管理架构、兼容性上进行分析。 市场地位 VMware在虚拟化的地位类似于大型存储中的EMC、小型机中IBM、网络中的思科…

阿里巴巴开源的缓存框架JetCache创建缓存
官网:https://github.com/alibaba/jetcache/wiki/CacheAPI_CN ======================= 多层嵌套缓存无效的问题: https://github.com/alibaba/jetcache/issues/424 某个service的方法加缓存注解,然后引用同一个类的另一个加缓存注解service的方法,这样必须在类里面注入…

【Python】百度翻译的爬虫实现(前篇)
该程序只能实现中文到英文的翻译 import requestsimport jsonurl "http://fanyi.baidu.com/basetrans"query_str input("请输入要翻译成英文的内容:")data{ "query": query_str,"from": "zh","to"…

github每次推送都要输入用户名和密码
/****************************************************************************** github每次推送都要输入用户名和密码* 说明:* 今天开始使用github管理一些东西,但是每次提交都出现要输入用户名和密码,* 这简直让人…

ELASTIC SEARCH 性能调优
ELASTICSEARCH 性能调优建议 创建索引调优 1.在创建索引的使用使用批量的方式导入到ES。 2.使用多线程的方式导入数据库。 3.增加默认刷新时间。 默认的刷新时间是1秒钟,这样会产生太多小的SEGMENT,导致未来的合并压力,如果调整这个大小&…

Android开源中国客户端学习 (自定义View)左右滑动控件ScrollLayout
左右滑动的控件我们使用的也是非常多了,但是基本上都是使用的viewpager 等 android基础的控件,那么我们有么有考虑过查看他的源码进行定制呢?当然,如果你自我感觉非常好的话可以自己定制一个,osc的ScrollLayout就是自己定义的View 和Viewpager的区别还是不小的 代码不是很多不…
【Python】有道翻译的爬虫实现(前篇)
import requestsimport jsonurl "http://fanyi.youdao.com/translate_o?smartresultdict&smartresultrule"data {"i": "我喜欢学习", "from": "AUTO", "to": "AUTO", "smartresult":&q…

自动生成纯文本表格的工具
https://tableconvert.com/?outputtext 有时候需要写文档的时候生成这种纯文本表格,这个工具真的很方便,贴上数据就可以了。

《Java编程思想》笔记13.字符串
点击进入我的博客 字符串操作是计算机程序设计中最常见的行为 13.1 不可变String String底层是由char[]实现的,是不可变的。看起来会改变String的方法,实际上都是创建了一个新的String对象,任何指向它的引用都不可能改变它本身的值。 13.2 重…
【Python】有道翻译的爬虫实现(后篇)
前面说到,有道翻译和百度翻译不同 (百度翻译是模拟iPhone手机,可能百度翻译用Pc端也会有类似的问题,有道翻译的User—Agent是Pc端) 每一次的salt和sign都不一样,这是什么原因产生的呢? 一、每…

Redis客户端JetCache的单机版和集群版的配置
jetcache基础应用参考这个:阿里巴巴开源的缓存框架JetCache创建缓存 1.JetCache的jedis配置 https://github.com/alibaba/jetcache/wiki/Config_CN jedis配置:apollo版 jetcache.remote.default.type = redis jetcache.remote.default.keyConvertor = fastjson jetcache.r…

5 分钟一次理解 Spring IOC !
今天我们分析一下 spring 的 IOC,梳理一下 IOC 和 DI 的概念与原理。在网上看到开涛有篇文章写的不错,提取其中一部分精华内容并做一些解读。 1.1.IOC是什么? Ioc—Inversion of Control,即“控制反转”,不是什么技术&…

工作两年的编程感想
2019独角兽企业重金招聘Python工程师标准>>> 工作已有两年了,两年不长也不短了,程序员的辛酸苦乐也都体验了一些,故写此博客既为留念,也为接下来的两年留下一个参考点。 首先需要声明的是,本人的工作是Java…

微服务重构心得
现在都在做微服务,看起来就是做服务拆分比较简单,但是实际上真正重构起来又遇到许许多多的问题。 微服务重构常见问题 1.领域驱动模型的困扰 比如听到很多理论比如领域驱动,那么到底需要不需要学习或者使用领域驱动呢? 2.系统的复杂性 重构的时候发现系统之间调用非常…

【Python】百度翻译的爬虫实现(后篇)
这个程序可以实现中英文的自动识别然后进行翻译 看着程序就很好理解。 import requestsimport jsonclass Translation():翻译def __init__(self,content):self.content contentself.url "http://fanyi.baidu.com/basetrans"self.headers {"User-Agent"…

美团即时物流的分布式系统架构设计
背景 美团外卖已经发展了五年,即时物流探索也经历了3年多的时间,业务从零孵化到初具规模,在整个过程中积累了一些分布式高并发系统的建设经验。最主要的收获包括两点: 即时物流业务对故障和高延迟的容忍度极低,在业务复…

Intellij IDEA单元测试提示Test events were not received
Intellij IDEA单元测试时提示Test events were not received 也就是可以运行test方法,也提示成功,但是看不到具体的执行结果。 Intellij IDEA从2019.2.1版本开始,会将Gradle管理的项目的测试代码,默认使用Gradle来运行࿰…

Linux下task_struct详解
背景:为了管理进程,操作系统必须对每个进程所做的事情进行清楚地描述,为此,操作系统使用数据结构来代表处理不同的实体,这个数据结构就是通常所说的进程描述符或进程控制块。在linux系统中,这就是task_stru…

【Python】数据提取xpath和lxml模块(豆瓣电影排行榜的爬虫)
xpath xpath:一门从html中提取数据的语言 xpath语法 1、选择节点(标签) /html/head/meta :能够选中html下的head下的所有的meta标签 2、// :能够从任意节点开始选择 //li:当前页面上所有的li标签 //html/head/link &a…

qt5.6.3下使用firebird
有人把firebird比作数据库界的瑞士军刀,想学习一下其在QT5.6中的使用,于是便开始了一场自己挖坑,自己埋的旅程。 环境说明:win7 64位QT5.6 mingw4.9 32位(好像官网上也没有64位,当然mingw也是32位的&#x…

【Python】数据提取xpath和lxml模块(糗事百科的爬虫)
程序中用到的一些零碎知识点: 一、列表推导式:帮助我们快速生成一堆数据的列表 1、format:字符串格式化的一种方式 >>> ["10月{}日".format(i) for i in range(1,10)] [10月1日, 10月2日, 10月3日, 10月4日, 10月5日, 1…

Linux Performance
性能专家Brendan Gregg的网站。 Linux性能 该页面链接到我创建的各种Linux性能材料,包括右侧的工具图。它们使用大字体来适合滑盖。您也可以将它们打印出来用于办公室墙壁。它们显示:Linux可观察性工具, Linux静态性能分析工具,…

07.LoT.UI 前后台通用框架分解系列之——强大的文本编辑器
LOT.UI分解系列汇总:http://www.cnblogs.com/dunitian/p/4822808.html#lotui LoT.UI开源地址如下:https://github.com/dunitian/LoTCodeBase/tree/master/LoTUI 先看在LoT.UI里面的应用效果图: 完整Demo:(https://gith…

workerman结合laravel开发在线聊天应用的示例代码
项目背景: 最近由于公司的业务需求,需要用到聊天功能。而且有比较多的个性化需求需要定制。之前使用别人的聊天组件是基于微擎的。如果要移植到普通的H5在逻辑修改还有定制上存在比较多的困难。为此只能克服困难,自己搭建一个吧 什么是Worker…

复杂系统设计 企业开发的困境
复杂系统设计源自我多年对企业复杂系统的设计的一些思考,类似日记吧,不断完善。 为什么从一个大公司的引入架构师甚至架构师组还是很难架构企业开发中的很多问题? 这些问题表现出架构上的复杂性,和业务上的复杂性。 有时候架构…