




已阅读5页,还剩5页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Socket-Select 2008-09-14 11:31 Select 在 Socket 编程中还是比较重要的,可是对于初学 Socket 的人来说都不 太爱用 Select 写程序,他们只是习惯写诸如 connect、accept、recv 或 recvfrom 这样的阻塞程序(所谓阻塞方式 block,顾名思义,就是进程或是线 程执行到这些函数时必须等 待某个事件的发生,如果事件没有发生,进程或线 程就被阻塞,函数不能立即返回)。 可是使用 Select 就可以完成非阻塞(所谓非阻塞方式 non-block,就是 进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返 回值的不同来反映函数的执行情况,如果事件发生则与阻塞方式相同,若事件 没有发生则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效 率较高) 方式工作的程序,它能够监视我们需要监视的文件描述符的变化情况 读写或是异常。下面详细介绍一下! Select 的函数格式: int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout); 先说明两个结构体: 第一,struct fd_set 可以理解为一个集合,这个集合中存放的是文件描述符 (file descriptor),即文件句柄,这可以是我们所说的普通意义的文件,当然 Unix 下任何设备、管道、FIFO 等都是文件形式,全部包括在内,所以毫 无疑 问一个 socket 就是一个文件,socket 句柄就是一个文件描述符。fd_set 集合 可以通过一些宏由人为来操作,比如清空集合 FD_ZERO(fd_set *),将一个给 定的文件描述符加入集合之中 FD_SET(int ,fd_set *),将一个给定的文件描 述符从集合中删除 FD_CLR(int ,fd_set*),检查集合中指定的文件描述符是否 可以读写 FD_ISSET(int ,fd_set* )。一会儿举例说明。 第二,struct timeval 是一个大家常用的结构,用来代表时间值,有两个成员, 一个是秒数,另一个是毫秒数。 具体解释 select 的参数: int maxfdp 是一个整数值,是指集合中所有文件描述符的范围,即所有文件描 述符的最大值加 1,不能错!在 Windows 中这个参数的值无所谓,可以设置不 正确。 fd_set *readfds 是指向 fd_set 结构的指针,这个集合中应该包括文件描述符, 我们是要监视这些文件描述符的读变化的,即我们关心是否可以从这些文件中 读取数据了,如果这个集合中有一个文件可读,select 就会返回一个大于 0 的 值,表示有文件可读,如果没有可读的文件,则根据 timeout 参数再判断 是否 超时,若超出 timeout 的时间,select 返回 0,若发生错误返回负值。可以传 入 NULL 值,表示不关心任何文件的读变化。 fd_set *writefds 是指向 fd_set 结构的指针,这个集合中应该包括文件描述 符,我们是要监视这些文件描述符的写变化的,即我们关心是否可以向这些文 件 中写入数据了,如果这个集合中有一个文件可写,select 就会返回一个大 于 0 的值,表示有文件可写,如果没有可写的文件,则根据 timeout 参数再判 断是否超时,若超出 timeout 的时间,select 返回 0,若发生错误返回负值。 可以传入 NULL 值,表示不关心任何文件的写变化。 fd_set *errorfds 同上面两个参数的意图,用来监视文件错误异常。 struct timeval* timeout 是 select 的超时时间,这个参数至关重要,它可以 使 select 处于三种状态,第一,若将 NULL 以形参传入,即不传入时间结构, 就是 将 select 置于阻塞状态,一定等到监视文件描述符集合中某个文件描述 符发生变化为止;第二,若将时间值设为 0 秒 0 毫秒,就变成一个纯粹的非阻 塞函数, 不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回 0,有变化返回一个正值;第三,timeout 的值大于 0,这就是等待的超时时间, 即 select 在 timeout 时间内阻塞,超时时间之内有事件到来就返回了,否则 在超时后不管怎样一定返回,返回值同上述。 返回值: 负值:select 错误 正值:某些文件可读写或出错 0:等待超时,没有可读写或错误的文件 在有了 select 后可以写出像样的网络程序来!举个简单的例子,就是从网络上 接受数据写入一个文件中。 例子: main() int sock; FILE *fp; struct fd_set fds; struct timeval timeout=3,0; /select 等待 3 秒,3 秒轮询,要非阻塞就 置 0 char buffer256=0; /256 字节的接收缓冲区 /* 假定已经建立 UDP 连接,具体过程不写,简单,当然 TCP 也同理,主机 ip 和 port 都已经给定,要写的文件已经打开 sock=socket(.); bind(.); fp=fopen(.); */ while(1) FD_ZERO( /每次循环都要清空集合,否则不能检测描述符变化 FD_SET(sock, /添加描述符 FD_SET(fp, /同上 maxfdp=sockfp?sock+1:fp+1; /描述符最大值加 1 switch(select(maxfdp,break; /select 错误,退出程序 case 0:break; /再次轮询 default: if(FD_ISSET(sock,/接受网络数据 if(FD_ISSET(fp,/写入文件 /buffer 清空; / end if break; / end switch /end while /end main 由于采用 select 机制, 因此当没有字符可读时, 程序处于阻塞状态,最小程度的占用 CPU 资源, 在同一台机器上执行一个 server 和若干个 client 时, 系统负载只有 0.1 左右, 而采 用原来的非阻塞通信方法, 只运行一个 server, 系统负载就可以达到 1.5 左右. 因此我们推 荐使用 select socket select()用法 一、winsock 中 #include 原型 int select( int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, const struct timeval* timeout ); nfds:本参数忽略,仅起到兼容作用。 readfds:(可选)指针,指向一组等待可读性检查的套接口。 writefds:(可选)指针,指向一组等待可写性检查的套接口。 exceptfds:(可选)指针,指向一组等待错误检查的套接口。 timeout:select()最多等待时间,对阻塞操作则为 NULL。 注释: 本函数用于确定一个或多个套接口的状态。对每一个套接口,调用者可查询 它的可读性、可写性及错误状态信息。用 fd_set 结构来表示一组等待检查的套 接 口。在调用返回时,这个结构存有满足一定条件的套接口组的子集,并且 select()返回满足条件的套接口的数目。有一组宏可用于对 fd_set 的操作, 这些宏与 Berkeley Unix 软件中的兼容,但内部的表达是完全不同的。 readfds 参数标识等待可读性检查的套接口。如果该套接口正处于监听 listen()状态,则若有连接请求到达,该套接口便被标识为可读,这样一个 accept()调用保证可以无阻塞完成。对其他套接口而言,可读性意味着有排队 数据供读取。或者对于 SOCK_STREAM 类型套接口来说,相对于该套 接口的虚套 接口已关闭,于是 recv()或 recvfrom()操作均能无阻塞完成。如果虚电路被 “优雅地”中止,则 recv()不读取数据立即返回;如 果虚电路被强制复位, 则 recv()将以 WSAECONNRESET 错误立即返回。如果 SO_OOBINLINE 选项被设置, 则将检查带外数据是否存在 (参见 setsockopt())。 writefds 参数标识等待可写性检查的套接口。如果一个套接口正在 connect()连接(非阻塞),可写性意味着连接顺利建立。如果套接口并未处于 connect()调用中,可写性意味着 send()和 sendto()调用将无阻塞完成。但 并未指出这个保证在多长时间内有效,特别是在多线程环境 中。 exceptfds 参数标识等待带外数据存在性或意味错误条件检查的套接口。请 注意如果设置了 SO_OOBINLINE 选项为假 FALSE,则只能用这种 方法来检查带 外数据的存在与否。对于 SO_STREAM 类型套接口,远端造成的连接中止和 KEEPALIVE 错误都将被作为意味出错。如果套接口正在进行 连接 connect() (非阻塞方式),则连接试图的失败将会表现在 exceptfds 参数中。 如果对 readfds、writefds 或 exceptfds 中任一个组类不感兴趣,可将它置 为空 NULL。 在 winsock.h 头文件中共定义了四个宏来操作描述字集。FD_SETSIZE 变量 用于确定一个集合中最多有多少描述字(FD_SETSIZE 缺省值 为 64,可在包含 winsock.h 前用#define FD_SETSIZE 来改变该值)。对于内部表示,fd_set 被 表示成一个套接口的队列,最后一个有效元素的后续元素为 INVAL_SOCKET。宏 为: FD_CLR(s,*set):从集合 set 中删除描述字 s。 FD_ISSET(s,*set):若 s 为集合中一员,非零;否则为零。 FD_SET(s,*set):向集合添加描述字 s。 FD_ZERO(*set):将 set 初始化为空集 NULL。 timeout 参数控制 select()完成的时间。若 timeout 参数为空指针,则 select()将一直阻塞到有一个描述字满足条件。否则的 话,timeout 指向一个 timeval 结构,其中指定了 select()调用在返回前等待多长时间。如果 timeval 为0,0,则 select()立即返回,这可用于探询所选套接口的状态。 如果处于这种状态,则 select()调用可认为是非阻塞的,且一切适用于非阻塞 调用的假设都 适用于它。举例来说,阻塞钩子函数不应被调用,且 WINDOWS 套 接口实现不应 yield。 返回值: select()调用返回处于就绪状态并且已经包含在 fd_set 结构中的描述字总 数;如果超时则返回 0;否则的话,返回 SOCKET_ERROR 错误,应用程序可通过 WSAGetLastError()获取相应错误代码。 错误代码: WSANOTINITIALISED:在使用此 API 之前应首先成功地调用 WSAStartup()。 WSAENETDOWN:WINDOWS 套接口实现检测到网络子系统失效。 WSAEINVAL:超时时间值非法。 WSAEINTR:通过一个 WSACancelBlockingCall()来取消一个(阻塞的)调用。 WSAEINPROGRESS:一个阻塞的 WINDOWS 套接口调用正在运行中。 WSAENOTSOCK:描述字集合中包含有非套接口的元素。 范例 : sock= socket(AF_INET,SOCK_STREAM,0); struct sockaddr_in addr; /告诉 sock 应该再什么地方 licence memset( addr.sin_family=AF_INET; addr.sin_port=htons(11111); /端口啦 addr.sin_addr.s_addr=htonl(INADDR_ANY); /在本机的所有 ip 上开 始监听 bind (sock,(sockaddr *)/bind listen(sock,5); /最大 5 个队列 SOCKET socka; /这个用来接受一个连接 fd_set rfd; / 描述符集 这个将用来测试有没有一个 可用的连接 struct timeval timeout; FD_ZERO( /总是这样先清空一个描述符集 timeout.tv_sec=60; /等下 select 用到这个 timeout.tv_usec=0; u_long ul=1; ioctlsocket(sock,FIONBIO, /用非阻塞的连接 /现在开始用 select FD_SET(sock, /把 sock 放入要测试的描述符集 就是说把 sock 放入 了 rfd 里面 这样下一步调用 select 对 rfd 进行测试的时候就会测试 sock 了 (因为我们将 sock 放入的 rdf) 一个描述符集可以包含多个被测试的描述符, if(select(sock+1, /一个用来测试读 一个用来测试写 FD_ZERO( FD_ZERO( FD_SET(socka,/把 socka 放入读描述符集 FD_SET(sockb,/把 sockb 放入读描述符集 FD_SET(socka,把 socka 放入写描述符集 FD_SET(sockb,把 sockb 放入写描述符集 if(SOCKET_ERROR!=select(0, 函数说明 select()用来等待文件描述词状态的改变。参数 n 代表最大的文件描述词加 1,参数 readfds、writefds 和 exceptfds 称为描述词组,是用来回传该描述 词的读,写或例外的状况。底下的宏提供了处理这三种描述词组的方式: FD_CLR(inr fd,fd_set* set);用来清除描述词组 set 中相关 fd 的位 FD_ISSET(int fd,fd_set *set);用来测试描述词组 set 中相关 fd 的位是否 为真 FD_SET(int fd,fd_set*set);用来设置描述词组 set 中相关 fd 的位 FD_ZERO(fd_set *set); 用来清除描述词组 set 的全部位 参数 timeout 为结构 timeval,用来设置 select()的等待时间,其结构定义如下 struct timeval time_t tv_sec; time_t tv_usec; ; 返回值 如果参数 timeout 设为 NULL 则表示 select()没有 timeout。 错误代码 执行成功则返回文件描述词状态已改变的个数
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 四川信息职业技术学院《土木工程施工组织》2023-2024学年第一学期期末试卷
- 门楼拆除重建施工方案
- 江西隧道保温施工方案
- 2025解除合同证明书范本
- 弱电手孔井施工方案
- 2025至2030年中国鳗饲料添加剂数据监测研究报告
- 2025至2030年中国铝质车用轮圈数据监测研究报告
- 别墅地下采光井施工方案
- 2025至2030年中国芥末油数据监测研究报告
- 2025福州房屋租赁合同简易版
- 深静脉导管维护流程
- 录音证据文字模版
- DL∕T 617-2019 气体绝缘金属封闭开关设备技术条件
- 班级管理(第3版)教学课件汇总全套电子教案(完整版)
- 冲压作业机械类作业活动风险分级管控清单
- TCVN-2622-越南建筑防火规范(中文版)
- 不负韶华只争朝夕-一模考试反思 课件-2021-2022学年高中主题班会(共17张PPT)
- 什么是管壁厚度号Sch
- 液压阀详细讲解课件
- DB13(J)∕T 256-2018 农村气代煤工程技术规程
- 小学数学基础知识大全
评论
0/150
提交评论