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. PHP性能优化 -理论篇

    什么情况下,遇到了PHP性能问题?    1 PHP语法使用的不恰当    2 使用PHP语言做不了它不擅长做的事    3 用php语言连接的服务不给力    4 PHP自身的短板    5 我也不 ...

  2. 如何在 Debian 9 下安装 LEMP 和 WHMCS 7.5

    WHMCS 7.5 发布了,它开始支持 PHP 7.2,这里就写个简单的教程记录一下安装方式. 1.准备工作 首先,我们需要按照 在Debian 9 / Debian 8 下使用源安装方式安装 LEM ...

  3. Tensorflow、Pytorch、Keras的多GPU使用

    Tensorflow.Pytorch.Keras的多GPU的并行操作 方法一 :使用深度学习工具提供的 API指定 1.1 Tesorflow tensroflow指定GPU的多卡并行的时候,也是可以 ...

  4. Thunder团队Final周贡献分分配结果

    小组名称:Thunder 项目名称:爱阅app 组长:王航 成员:李传康.翟宇豪.邹双黛.苗威.宋雨.胡佑蓉.杨梓瑞 分配规则 则1:基础分,拿出总分的20%(8分)进行均分,剩下的80%(32分)用 ...

  5. 20172332『Java程序设计』课程结对编程练习_四则运算第二周阶段总结

    20172313『Java程序设计』课程结对编程练习_四则运算第二周阶段总结 小组成员 20172326康皓越 20172313余坤澎 20172332于欣月 小组编程照片 设计思路 设计一个生成符号 ...

  6. winform界面之固定大小随dpi

    场景: 已经更改成大小可随dpi改变,可是在用applyresoures()之后(添加更改语言功能),发现控件大小失真. 分析:applyresoures()是把该控件的属性改为程序设计的固定大小,不 ...

  7. XCode 6.4 Alcatraz 安装的插件不可用

    升级Xcode 6.4后插件都不可用了,解决办法: 1.在 Alcatraz中删除插件并退出Xcode: 2.重新打开Xcode 并安装: 3.退出Xcode: 4.进入Xcode,会提示如图,点击 ...

  8. hdu 5524

    由于是完全二叉树,所以我们可以预先知道整棵树的形状,因此可以判断根节点的两个子节点哪个是满二叉树,哪个不是满二叉树(必然是一边满,一边不满),对于满的子节点,我们可以直接求出它的不同子树的个数,也就是 ...

  9. oracle impdp导入时 提示“ORA-39002: 操作无效 ORA-39070: 无法打开日志文件 ”

    第一步:首先使用DBA权限的用户创建directory,我使用system ,可以在服务器本地创建,也可以远程连接sqlplus进行创建,使用的将是服务器上面的路径.要确保创建directory时,操 ...

  10. dat.gui 上手

    dat.gui是款神器产品.一个调试利器.但是用起来很简单很简单 1:引用dat.gui.js. 2:实例化   this.gui = new dat.GUI(); 3:创建可设置一个数据对象.例如v ...