1. 共有6种类型套接字I/O模型。blocking(阻塞),select(选择),WSAAsyncSelect(异步选择),WSAEventSelect(事件选择),overlapped(重叠),completionport(完成端口)。
  2. .select
  3. 之所以称select模型,是因为工作原理是利用select函数实现对I/O的管理。
  4. select可用于判断套接字上是否存在数据,或者能否向一个套接字写入数据,之所以要设计这个函数,其目的是防止应用程序在套接字处于阻塞模式时,在I/O绑定调用(如sendrecv)过程中进入阻塞状态;同时也放在套接字处于非阻塞模式中时,产生WSAEWOULDBLOCK错误,除非满足事先用参数规定的条件,否则select函数在进行I/O操作时会阻塞。
  5. int select(
  6. int nfds,
  7. fd_set FAR* readfds,
  8. fd_set FAR* writefds,
  9. fd_set FAR* exceptfds,
  10. const struct timeval FAR* timeout
  11. );
  12. nfds会被忽略,之所以保留是为了与早期套接字兼容
  13. 3fd_sedreadfds用于检测可读性,writefds用于检测可写性,exceptfds用于外地数据,从根本上讲,fd_set数据类型代表着一系列特定套接字结合。
  14. readfds集合包括符合下述任何一个条件的套接字:
  15. .有数据可以读入
  16. .连接已经被关闭,终止或重启
  17. .假如已调用了listen,而且有一个连接正处于搁置状态,那么accept调用会成功
  18. writefds集合包括符合下述任何一个条件的套接字:
  19. .有数据可以发出
  20. .如果正在对一个非阻塞连接调用进行处理,则连接就成功
  21. exceptfds集合包括符合下述任何一个条件的套接字:
  22. .如果正在对一个非阻塞连接调用进行处理,连接尝试将会失败
  23. .有OOBout-of-band,外地)数据可供读写
  24. 假设我们想测试一个套接字是否可读,必须将套接字添加到readfds集合中,在等待select函数完成。当select调用完成后,必须判断这个套接字是否仍为readfds中的一部分。若是,则表明该套接字可读,可立即进行读取数据。在3个参数中,任何两个都可以是NULL,但至少有一个不能为NULL,在任何不为空的集合中,必须包含至少一个套接字句柄,否则select没有任何东西可以等待。timeout对应的是一个指针,指向一个timeval结构,用于决定select等待I/O操作完成时,最多等待多长时间。如果timeout是一个空指针,那么select调用会无限期处于阻塞状态,直到至少有一个描述符与指定条件相符才结束。
  25. struct timeval
  26. {
  27. long tv_sec;//秒为单位指定等待时间
  28. long tv_usec;//以毫秒为单位指定等待时间
  29. };
  30. //若将时间设置为{0,0}表明select会立即返回。处于对性能考虑,应避免这么设置
  31. fd_set集合进行处理与检查:
  32. FD_ZERO(*set);//将set初始化为空集合,集合在使用前都要清空
  33. FD_CLR(s, *set);//从set中删除套接字s
  34. FD_ISSET(s, *set);//检测s是否是set中的一个成员,如果是,返回TRUE
  35. FD_SET(s, *set);//将套接字s加入到set中
  36. 采用以下步骤便可完成select操作一个或多个套接字句柄的全过程:
  37. .使用FD_ZERO初始化自己感兴趣的每个fd_set
  38. .使用FD_SET将套接字句柄分配给自己感兴趣的fd_set
  39. .调用select函数,然后等待直到I/O活动在在指定的fd_set集合中设置好了一个或多个套接字句柄。select完成后,会返回在所有fd_set集合中设置的套接字句柄总数,并对每个集合进行相应的更新
  40. .根据select的返回值,应用程序便可判断哪些套接字存在着被搁置的I/O操作--具体的方法是使用FD_ISSET宏,对每个fd_set进行检查
  41. .知道了每个集合中被挂起的I/O操作之后,对I/O进行处理,然后返回步骤1,继续处理select
  42. select返回后,它会修改每个fd_set结构。删除那些不存在被挂起的I/O操作的套接字句柄。
  43. 示例代码
  44. SOCKET s;
  45. fd_set fdread;
  46. int ret;
  47.  
  48. //创建套接字,接受连接
  49.  
  50. //在套接字上管理I/O
  51. while(true)
  52. {
  53. //在调用select前,清楚读出集
  54. FD_ZERO(&fdread);
  55. //将s添加到读出集
  56. FD_SET(s, &fdread);
  57. if((ret=select(, &fdread, NULL, NULL, NULL))==SOCKET_ERROR)
  58. {
  59. //条件出错
  60. }
  61.  
  62. if(ret>)
  63. {
  64. //
  65. //
  66. if(FD_ISSET(s, &fdread))
  67. {
  68. //套接字s上已发生了一个事件
  69. }
  70. }
  71. }
  72. 使用select的优势是能够从当个线程的多个套接字上进行多重连接及I/O
  73.  
  74. =======================================================================
  75. 客户端代码:
  76. 这是一个最简单的客户端代码,负责发送数据,然后接受返回。
  77. #include<stdio.h>
  78. #include<winsock2.h>
  79. #pragma comment(lib, "ws2_32.lib")
  80.  
  81. #define SERVER_IP "192.168.1.222"
  82. #define PORT 5150
  83. #define MSGSIZE 1024
  84.  
  85. int main()
  86. {
  87. WSADATA wsaData;
  88. SOCKET sClient;
  89. SOCKADDR_IN server;
  90. char szMessage[MSGSIZE];
  91. int ret;
  92.  
  93. WSAStartup(MAKEWORD(,), &wsaData);
  94. sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  95. memset(&server, , sizeof(server));
  96. server.sin_family = AF_INET;
  97. server.sin_port = htons(PORT);
  98. server.sin_addr.s_addr = inet_addr(SERVER_IP);
  99.  
  100. connect(sClient, (sockaddr*)&server, sizeof(SOCKADDR_IN));
  101. while(TRUE)
  102. {
  103. printf("Send:");
  104. gets(szMessage);
  105. send(sClient, szMessage, strlen(szMessage), );
  106. ret = recv(sClient, szMessage, MSGSIZE, );
  107. szMessage[ret] = '\0';
  108. printf("Received [%d bytes]: '%s'\n", ret, szMessage);
  109. }
  110. closesocket(sClient);
  111. WSACleanup();
  112.  
  113. //system("pause");
  114. return ;
  115. }
  116.  
  117. 服务端代码:
  118. 这是异步模型中最简单的一种,服务器端的几个主要流程如下:
  119. .创建监听套接字,绑定,监听;
  120. .创建工作者线程;
  121. .创建一个套接字数组,用来存放当前所有活动的客户端套接字,每accept一个连接就更新一次数组;
  122. .接受客户端的连接。
  123. #include<stdio.h>
  124. #include<winsock2.h>
  125. #pragma comment(lib, "ws2_32.lib")
  126.  
  127. #define PORT 5150
  128. #define MSGSIZE 1024
  129.  
  130. int g_iTotalConn = ;
  131. SOCKET g_CliSocketArr[FD_SETSIZE];
  132. DWORD WINAPI WorkerThread(LPVOID lpParam);
  133.  
  134. int main()
  135. {
  136. WSADATA wsaData;
  137. SOCKET sListen, sClient;
  138. SOCKADDR_IN local, client;
  139. int iAddrSize = sizeof(SOCKADDR_IN);
  140. DWORD dwThreadId;
  141.  
  142. WSAStartup(MAKEWORD(,), &wsaData);
  143. sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  144. memset(&local, , sizeof(SOCKADDR_IN));
  145. local.sin_family = AF_INET;
  146. local.sin_port = htons(PORT);
  147. local.sin_addr.s_addr = htonl(INADDR_ANY);
  148.  
  149. bind(sListen, (sockaddr*)&local, sizeof(SOCKADDR_IN));
  150. listen(sListen, );
  151.  
  152. CreateThread(NULL, , WorkerThread, NULL, , &dwThreadId);
  153.  
  154. while(TRUE)
  155. {
  156. sClient = accept(sListen, (sockaddr*)&client, &iAddrSize);
  157. printf("Accepted client:%s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
  158. g_CliSocketArr[g_iTotalConn++] = sClient;
  159. }
  160.  
  161. return ;
  162. }
  163.  
  164. DWORD WINAPI WorkerThread(LPVOID lpParam)
  165. {
  166. fd_set fdread;
  167. int ret;
  168. int i;
  169. struct timeval tv = {,};
  170. char szMessage[MSGSIZE];
  171. while(TRUE)
  172. {
  173. FD_ZERO(&fdread);
  174. for(i=; i<g_iTotalConn; ++i)
  175. {
  176. FD_SET(g_CliSocketArr[i], &fdread);
  177. }
  178. ret = select(, &fdread, NULL, NULL, NULL);
  179. if( == ret)
  180. {
  181. continue;
  182. }
  183. for(i=; i<g_iTotalConn; ++i)
  184. {
  185. if(FD_ISSET(g_CliSocketArr[i], &fdread))
  186. {
  187. ret = recv(g_CliSocketArr[i], szMessage, MSGSIZE, );
  188. if( == ret || (ret==SOCKET_ERROR && WSAGetLastError()==WSAECONNRESET))
  189. {
  190. printf("Client socket %d closed.\n", g_CliSocketArr[i]);
  191. closesocket(g_CliSocketArr[i]);
  192. if(i<g_iTotalConn-)
  193. {
  194. g_CliSocketArr[i--] = g_CliSocketArr[--g_iTotalConn];
  195. }
  196. }
  197. else
  198. {
  199. szMessage[ret] = '\0';
  200. send(g_CliSocketArr[i], szMessage, strlen(szMessage), );
  201. }
  202. }
  203. }
  204. }
  205. }

套接字I/O模型-select的更多相关文章

  1. 套接字I/O模型之WSAEventSelect

    今天我又学习了一种新的套接字I/O模型------WSAEventSelect,他与WSAAsyncSelect一样也是一种异步事件通知模型,不同的是WSAAsyncSelect是与窗口句柄关联在一起 ...

  2. 套接字I/O模型-WSAAsyncSelect

    利用这个异步I/O模型,应用程序可在一个套接字上接收以Windows消息为基础的网络事件通知.WSAAsyncSelect和WSAEventSelect提供读写数据能力的异步通知,但它们不提供异步数据 ...

  3. Linux下套接字具体解释(三)----几种套接字I/O模型

    參考: 网络编程–IO模型演示样例 几种server端IO模型的简介及实现 背景知识 堵塞和非堵塞 对于一个套接字的 I/O通信,它会涉及到两个系统对象.一个是调用这个IO的进程或者线程,还有一个就是 ...

  4. Windsock套接字I/O模型学习 --- 第二章

    1. select模型 select模型主要借助于apiselect来实现,所以先介绍一下select函数 int select( int nfds, // 忽略,仅是为了与 Berkeley 套接字 ...

  5. Windsock套接字I/O模型学习 --- 第一章

    1. I/O模型共有以下几种: 阻塞(blocking)模型 选择(select)模型 WSAAsyncSelect模型 WSAEventSelect模型 重叠(overlapped)模型 完成端口( ...

  6. 套接字I/O模型-重叠I/O

    重叠模型的基本设计原理是让应用程序使用重叠的数据结构,一次投递一个或多个WinsockI/O请求.针对那些提交的请求,在它们完成之后,应用程序可为它们提供服务.模型的总体设计以Windows重叠I/O ...

  7. 套接字I/O模型-完成端口IOCP

    “完成端口”模型是迄今为止最为复杂的一种I/O模型.然而,假若一个应用程序同时需要管理为数众多的套接字,那么采用这种模型,往往可以达到最佳的系统性能!但不幸的是,该模型只适用于Windows NT和W ...

  8. 套接字I/O模型-WSAEventSelect(转载)

    和WSAAsyncSelect类似,它也允许应用程序在一个或多个套接字上,接收以事件为基础的网络事件通知. 该模型最主要的区别是在于网络事件是由对象句柄完成的,而不是通过窗口例程完成. 事件通知 事件 ...

  9. Windsock套接字I/O模型学习 --- 第三章

    1. WSAAsyncSelect 模型 WSAAsyncSelect 模型比较简单,是为了适应Windows的消息驱动环境而设置的,WSAAsyncSelect 函数自动把套接字设为非阻塞模式.MF ...

随机推荐

  1. JS获取客户端Mac和IP

    JS获取硬件信息是通过ActiveX进行获取的,因此只能IE浏览器支持,火狐不支持 而且必须降低浏览器安全级别,因此不到万不得以一般不会采用这种方式 <html> <head> ...

  2. hdoj-2025a

    #include "stdio.h"#include "string.h"void compare(int n,char s[],char &k);vo ...

  3. H5+app前端后台ajax交互总结

    流应用开发 1.前端是HBuilder 编写的html页面,UI控件用MUI: 2.后台用Eclipse开发的Servlet做控制器: 3.前后台交互用MUI的Ajax. 在Hbuilder中选择在安 ...

  4. 51 nod 机器人走方格

    从一个长方形的方格的右上角 走到 左下角 , 问一共有多少种不同的路线可以达到 . #include<stdio.h> #include<string.h> #include& ...

  5. webservice发布在外网上的在system.web中加入这个就好使了

    <webServices>         <protocols>            <add name="HttpSoap"/>      ...

  6. 学习笔记:iPhone终极指南、手机端、浏览器各种规范

    手机图解参考:http://www.paintcodeapp.com/news/iphone-6-screens-demystified 手机图标尺寸参考:https://developer.appl ...

  7. Milk

    Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other) Total Submission(s) ...

  8. 把input类型剔出来

    <!doctype html public "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. mysql主从同步mysql slave_io_running:no的解决方案

    在主从同步的时候出现slave_io_running:no 问题,于是查看mysqld.log日志,发现时1042错误 解决方案: 编辑/etc/my.cnf,在:[mysqld]内添加一行:skip ...

  10. Inno Setup使用上的几个问题

    Inno Setup使用上的几个问题 分类: Install Setup 2013-02-02 15:48 1781人阅读 评论(0) 收藏 举报 Inno Setup使用上的几个问题: [问题一:I ...