您当前的位置: 首页 > 

phymat.nico

暂无认证

  • 2浏览

    0关注

    1967博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Select模型原理

phymat.nico 发布时间:2015-01-10 10:14:08 ,浏览量:2

Select模型原理

利用select函数,判断套接字上是否存在数据,或者能否向一个套接字写入数据。目的是防止应用程序在套接字处于锁定模式时,调用recv(或send)从没有数据的套接字上接收数据,被迫进入阻塞状态。

 

select参数和返回值意义如下:

int select (

 IN int nfds,                           //0,无意义

 IN OUT fd_set* readfds,      //检查可读性

 IN OUT fd_set* writefds,     //检查可写性

 IN OUT fd_set* exceptfds,  //例外数据

 IN const struct timeval* timeout);    //函数的返回时间

 

struct  timeval {

        long    tv_sec;        //秒

        long    tv_usec;     //毫秒

};

select返回fd_set中可用的套接字个数。

 

fd_set是一个SOCKET队列,以下宏可以对该队列进行操作:

FD_CLR( s, *set) 从队列set删除句柄s;

FD_ISSET( s, *set) 检查句柄s是否存在与队列set中;

FD_SET( s, *set )把句柄s添加到队列set中;

FD_ZERO( *set ) 把set队列初始化成空队列.

 

Select工作流程

1:用FD_ZERO宏来初始化我们感兴趣的fd_set。

也就是select函数的第二三四个参数。

2:用FD_SET宏来将套接字句柄分配给相应的fd_set。

如果想要检查一个套接字是否有数据需要接收,可以用FD_SET宏把套接接字句柄加入可读性检查队列中

3:调用select函数。

如果该套接字没有数据需要接收,select函数会把该套接字从可读性检查队列中删除掉,

4:用FD_ISSET对套接字句柄进行检查。

如果我们所关注的那个套接字句柄仍然在开始分配的那个fd_set里,那么说明马上可以进行相应的IO操 作。比如一个分配给select第一个参数的套接字句柄在select返回后仍然在select第一个参数的fd_set里,那么说明当前数据已经来了, 马上可以读取成功而不会被阻塞。

[cpp] view plain copy print ?
  1. #include      
  2. #include      
  3.   
  4. #define PORT  5150     
  5.   
  6. #define MSGSIZE  1024     
  7.   
  8. #pragma comment(lib, "ws2_32.lib")     
  9.   
  10. int g_iTotalConn1 = 0;    
  11. int g_iTotalConn2 = 0;     
  12.   
  13. SOCKET g_CliSocketArr1[FD_SETSIZE];    
  14. SOCKET g_CliSocketArr2[FD_SETSIZE];    
  15.   
  16. DWORD WINAPI WorkerThread1(LPVOID lpParam);     
  17. int CALLBACK ConditionFunc1(LPWSABUF lpCallerId,LPWSABUF lpCallerData, LPQOS lpSQOS,LPQOS lpGQOS,LPWSABUF lpCalleeId, LPWSABUF lpCalleeData,GROUP FAR * g,DWORD dwCallbackData);  
  18.   
  19. DWORD WINAPI WorkerThread2(LPVOID lpParam);     
  20. int CALLBACK ConditionFunc2(LPWSABUF lpCallerId,LPWSABUF lpCallerData, LPQOS lpSQOS,LPQOS lpGQOS,LPWSABUF lpCalleeId, LPWSABUF lpCalleeData,GROUP FAR * g,DWORD dwCallbackData);  
  21.   
  22.   
  23. int main(int argc, char* argv[])     
  24. {     
  25.  WSADATA wsaData;     
  26.  SOCKET sListen, sClient;     
  27.  SOCKADDR_IN local, client;     
  28.  int iAddrSize = sizeof(SOCKADDR_IN);     
  29.  DWORD dwThreadId;     
  30.  // Initialize windows socket library     
  31.  WSAStartup(0x0202, &wsaData);     
  32.  // Create listening socket     
  33.  sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);     
  34.  // Bind     
  35.   
  36.  local.sin_family = AF_INET;     
  37.  local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);     
  38.  local.sin_port = htons(PORT);     
  39.  bind(sListen, (sockaddr*)&local, sizeof(SOCKADDR_IN));     
  40.   
  41.  // Listen     
  42.   
  43.  listen(sListen, 3);     
  44.   
  45.  // Create worker thread     
  46.   
  47.  CreateThread(NULL, 0, WorkerThread1, NULL, 0, &dwThreadId);    
  48. // CreateThread(NULL, 0, WorkerThread2, NULL, 0, &dwThreadId);    
  49.   
  50.  while (TRUE)      
  51.  {       
  52.   sClient = WSAAccept(sListen, (sockaddr*)&client, &iAddrSize, ConditionFunc1, 0);  
  53.   printf("1:Accepted client:%s:%d:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port), g_iTotalConn1);     
  54.   g_CliSocketArr1[g_iTotalConn1++] = sClient;    
  55. /*          
  56.   sClient = WSAAccept(sListen, (sockaddr*)&client, &iAddrSize, ConditionFunc2, 0); 
  57.   printf("2:Accepted client:%s:%d:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port), g_iTotalConn2);    
  58.   g_CliSocketArr2[g_iTotalConn2++] = sClient;   */  
  59.   
  60.  }     
  61.  return 0;     
  62. }     
  63.   
  64. DWORD WINAPI WorkerThread1(LPVOID lpParam)     
  65. {     
  66.  int i;     
  67.  fd_set fdread;     
  68.  int ret;     
  69.  struct timeval tv = {1, 0};     
  70.  char szMessage[MSGSIZE];     
  71.  while (TRUE)      
  72.  {     
  73.   FD_ZERO(&fdread);   //1清空队列  
  74.   for (i = 0; i 
关注
打赏
1659628745
查看更多评论
立即登录/注册

微信扫码登录

0.0455s