select模型支持IO多路复用,select函数如下

int select (
IN int nfds, //windows下无意义,linux有意义
IN OUT fd_set* readfds, //检查可读性
IN OUT fd_set* writefds, //检查可写性
IN OUT fd_set* exceptfds, //例外数据
IN const struct timeval* timeout); //函数的返回时间

逐个解释每个参数意义:

nfds:一个整型变量,表示比最大文件描述符+1

readfds: 这个集合监测读事件的描述符,将要监听

读事件的文件描述符放入readfds中,通过调用select,

readfds中将没有就绪的读事件文件描述符清除,留下

就绪的读事件描述符,可以通过read或者recv来处理

writefds:这个集合监测写事件的描述符,将要监听的

写事件的文件描述符放入writefds中,通过调用select,

writefds中没有就绪的写事件文件描述符被清除,留下

就绪的写事件描述符,可以通过write或者send来处理。

execptfds:这个集合在调用select后会存有错误的文件

描述符。根据Linux网络网络编程第二版中介绍,可以

监视带外数据OOB,带外数据使用MSG_OOB标志发送

到套接字上,当select()函数返回的时候,readfds将清除

其中的其他文件描述符,留下OOB数据

函数返回值:

当返回0时表示超时,-1表示有错误,大于0表示没有错误。

当监视文件集中有文件描述符符合要求,即读文件描述符集

合中有文件可读,写文件描述符集合中有文件可写,或者

错误文件描述符集合中有错误的描述符,都会返回大于0的数。

timeval结构体解释

struct  timeval {
long tv_sec; //秒
long tv_usec; //毫秒
};

timeval指针为NULL,表示一直等待,直到有符合条件的描述符

触发select返回

如果timeval中个参数均为0,表示立即返回,否则在select没有

符合条件的描述符,等待对应的时间和,然后返回。

另外需要了解一些select的操作宏函数

fd_set是一个SOCKET队列,以下宏可以对该队列进行操作:
FD_CLR( s, fd_set *set) 从队列set删除句柄s;
FD_ISSET( s,fd_set *set) 检查句柄s是否存在与队列set中;
FD_SET( s, fd_set *set )把句柄s添加到队列set中;
FD_ZERO( fd_set *set ) 把set队列初始化成空队列.

看一个select的使用示例

//前面是服务器socket的创建,绑定和监听

int  listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// Bind local.sin_family = AF_INET;
local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
local.sin_port = htons(PORT);
bind(listenSocket, (sockaddr*)&local, sizeof(SOCKADDR_IN)); // Listen listen(listenSocket, );
//设置非阻塞
fcntl(listenSocket, F_SETFL, O_NONBLOCK ); //这个使用来统计所有已经连接上来的文件描述符,
//也可以用数组表示,只是遍历的时候要根据数据结构进行更改
FD_SET socketSet;
FD_SET writeSet;
FD_SET readSet; //清空 socketSet
FD_ZERO(&socketSet);
//将文件描述符放入 socketSet,
//用于accept
FD_SET(listenSocket,&socketSet);
//统计最大的socket
int maxfd = listenSocket;
int conNum = ;
//数组存储连接的socket
int connectArray[]={};
while(true)
{
//清空读写集合
FD_ZERO(&readSet);
FD_ZERO(&writeSet);
//读写都监听
readSet=socketSet;
writeSet=socketSet; //同时检查套接字的可读可写性。
//为等待时间传入NULL,则永久等待。传入0立即返回。不要勿用。
int ret=select(maxfd,&readSet,&writeSet,NULL,NULL);
if(ret==-)
{
return false;
}
sockaddr_in addr;
int len=sizeof(addr);
//是否存在客户端的连接请求。
//在readset中会返回已经调用过listen的套接字
if(FD_ISSET(listenSocket,&readSet))
{
acceptSocket=accept(listenSocket,(sockaddr*)&addr,&len);
if(acceptSocket==INVALID_SOCKET)
{
return false;
}
else
{
//大于我们最大的监听数量了
if(conNum > )
{
return false;
}
//更新数组
connectArray[conNum] = acceptSocket;
//设置非阻塞
fcntl(connectArray[conNum], F_SETFL, O_NONBLOCK );
//加到socketset里,以后赋值给读写集合
FD_SET(connectArray[conNum],&socketSet);
if(acceptSocket > maxfd)
{
maxfd = acceptSocket;
}
conNum++;
}
} for(int i=;i<conNum;i++)
{
//判断是否有读事件
if(FD_ISSET(connectArray[i],&readSet))
{
//调用recv,接收数据。
//判断recv结果,为0则客户端断开,
//那么调用FD_CLR并关闭对应的socket
}
//判断是否有写事件
if(FD_ISSET(connectArray[i],&writeSet)
{
//调用send,发送数据。
//判断send结果,为0客户端断开,
//那么调用FD_CLR并关闭对应的socket
}
}
}

上面的例子结合了网上提供的一些demo,其实writeSet不一定要放入socket,当某个socket需要send内容时

再调用FD_SET(socket,&writeSet),写成功后再调用FD_CLR(socket,&writeSet);避免造成busyloop,

因为当缓冲区非空时,写事件是一直就绪的。

我的微信公众号,定期推送一些技术总结,一起努力吧。

select网络模型知识总结的更多相关文章

  1. linux select 网络模型

    io模型: 同步IO: 阻塞形式,非阻塞形式(轮询).信号驱动IO.IO复用(select, poll, epoll): 异步io:aio_read() 典型场景: 1.客户端处理多种IO------ ...

  2. python 3下基于select模型的事件驱动机制程序

    它的基本原理就是select/epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程.它的流程如图: 当用户进程调用了select,那么整个 ...

  3. EasyDarwin开源流媒体server将select改为epoll的方法

    本文来自EasyDarwin团队Fantasy(fantasy(at)easydarwin.org) 一. EasyDarwin网络模型介绍 EventContext负责监听全部网络读写事件.Even ...

  4. EasyDarwin开源流媒体服务器将select改为epoll的方法

    本文来自EasyDarwin团队Fantasy(fantasy(at)easydarwin.org) 一. EasyDarwin网络模型介绍 EventContext负责监听所有网络读写事件,Even ...

  5. 开源流媒体服务器EasyDarwin支持epoll网络模型,大大提升流媒体服务器网络并发性能

    经过春节前后将近2个月的开发和稳定调试.测试,EasyDarwin开源流媒体服务器终于成功将底层select网络模型修改优化成epoll网络模型,将EasyDarwin流媒体服务器在网络处理的效率上提 ...

  6. Django源码分析之启动wsgi发生的事

    前言 ​ 好多人对技术的理解都停留在懂得使用即可,因而只会用而不会灵活用,俗话说好奇害死猫,不然我也不会在凌晨1.48的时候决定写这篇博客,好吧不啰嗦了 ​ 继续上一篇文章,后我有个问题(上文:&qu ...

  7. 最全的ORACLE-SQL笔记

    -- 首先,以超级管理员的身份登录oracle sqlplus sys/bjsxt as sysdba --然后,解除对scott用户的锁 alter user scott account unloc ...

  8. Mysql中较为复杂的分组统计去重复值

    这是我的代码: 前提是做了一个view:att_sumbase 首先分开统计每天的中午.下午饭点人数,这时需要分别去除中午和下午重复打卡的人.用了记录集的交,嵌套select的知识. 注意不能直接使用 ...

  9. django源码分析

    原文网址 https://www.jianshu.com/p/17d78b52c732?utm_campaign=maleskine&utm_content=note&utm_medi ...

随机推荐

  1. CDQ分治_占坑

    准备系统地学习一波CDQ分治,持续更新中... 首先,CDQ分治也还是分治的一种,只不过普通分治是独立的解决两个子问题,而CDQ分治还要计算第一个子问题对于第二个的影响. CDQ分治几乎都是用来解决多 ...

  2. node.js常用方法

    1.获取真实地址 function getClientIp(req) { return req.headers['x-forwarded-for'] || req.connection.remoteA ...

  3. 王者荣耀交流协会第三次Scrum立会

    会议时间:2017年10月22号   18:00-18:32,时长32分钟. 会议地点:中快餐厅二楼第二排倒数第二个桌子. 立会内容: 1.每位同学汇报了今日工作. 2.通过讨论我们决定用存excel ...

  4. Python:内建函数zip

    1.语法 zip([iterable,...]) [说明]:iterable——一个或多个迭代器 2.功能 zip()函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个的元组,然后返回由这 ...

  5. CSS3:不可思议的border属性

    在CSS中,其border属性有很多的规则.对于一些事物,例如三角形或者其它的图像,我们仍然使用图片代替.但是现在就不需要了,我们可以用CSS形成一些基本图形,我分享了一些关于这方面的技巧. 1.正三 ...

  6. 【第一周】PSP

    日期 C类别 C内容 S开始时间 E结束时间 I间隔(单位:分钟) T净时间(单位:分钟) 9月2日 编程 词频统计 7:35 9:35 10 110 9月3日 读书 构建之法 8:00 9:00 5 ...

  7. 用putty玩linux的时候由于以前用window 习惯写完东西按一下ctrl+s 保存

    问题描述:用putty玩linux的时候由于以前用window 习惯写完东西按一下ctrl+s 保存,但是在putty一按下就不能再输入了.后来查找到:ctrl+s 是putty的一个命令大概是这样子 ...

  8. react-router之代码分离

    概念 无需用户下载整个应用之后才能访问访问它.即边访问边下载.因此我们设计一个组件<Bundle>当用户导航到它是来动态加载组件. import loadSomething from 'b ...

  9. Linux 下定位java应用 cpu高的原因(转)

    使用场景: 遇到Linux下java应用cpu占用很高的时候,我们很想知道此时的应用到底在做什么导致资源的消耗. 方便我们进一步定位和优化~ 1.查询cpu耗用top5的进程(你也可以top10) [ ...

  10. Vue使用,异步获取日期时间后格式成"/Date(1333245600000+0800)/" 转换成正常格式

    js从后台mvc中日期获取,结果格式成"/Date(1333245600000+0800)/"了,当然不能这样展显给用户了,要转换,方法如下: function data_stri ...