TCP非阻塞设置

 
  

套接字的默认状态是阻塞的,这就意味着当发出一个不能立即完成的套接字调用时,其进程将被投入睡眠,等待响应操作完成,可能阻塞的套接字调用可分为以下四类:

(1) 输入操作,包括read,readv,recv,recvfrom,recvmsg;

(2) 输出操作,包括write,writev,send,sendto,sendmsg;

(3) 接受外来连接,即accept函数。

accept在阻塞模式下,没有新连接时,线程会进入睡眠状态;非阻塞模式下,没有新连接时,立即返回WOULDBLOCK错误。

(4) 发起外出连接,即tcp的connect函数;

connect在阻塞模式下,仅TCP连接建立成功或出错时才返回,分几种具体的情况,这里不再叙述;非阻塞模式下,该函数会立即返回INPROCESS错误(需用select检测该连接是否建立成功

linux下和windows下设置阻塞和非阻塞的几种方式:

linux:

fcntl(socket, F_SETFL, flags | O_NONBLOCK);

windows:

ioctlsocket(socket,FIONBIO,1);//FIONBIO :允许或禁止套接口s的非阻塞模式 ;  0是堵塞

ioctlsocket,WSAAsyncselect()和WSAEventselect()


代码:

  1. static int tcp_send(SOCKET sockClient,const char* request_head,long slen,bool &iFlag)  
  2. {  
  3.       
  4.     int iRet = 0;  
  5.     int i = 0;  
  6.     long already_bytes = 0;  
  7.     int lenSend = 0;  
  8.   
  9.     fd_set fd;  
  10.     timeval tiout;  
  11.     tiout.tv_sec = 1;  
  12.     tiout.tv_usec = 0;  
  13.   
  14.     for (i = 0;(i < 3) && (!iFlag); i++)//iFlag 即bexit时退出,防止在此循环中等待事件过长  
  15.     {  
  16.         FD_ZERO(&fd);  
  17.         FD_SET(sockClient, &fd);  
  18.         iRet = select(sockClient+1,NULL,&fd,NULL,&tiout);  
  19.   
  20.         if (iRet > 0  && FD_ISSET(sockClient,&fd))  
  21.         {   
  22.             lenSend = send(sockClient, request_head+already_bytes, slen-already_bytes, 0);  
  23.             if(lenSend == -1)  
  24.             {  
  25.                 continue;         
  26.             }  
  27.            already_bytes += lenSend;  
  28.            if(already_bytes == slen)  
  29.            {  
  30.                return 0;  
  31.            }  
  32.         }  
  33.         else // 无论出错超时还是暂时没有等到,都尝试3次  
  34.         {  
  35.             continue;  
  36.         }  
  37.           
  38.     }  
  39.   
  40.     return -1;  
  41. }  
  42.   
  43. static int tcp_connect(SOCKET sockClient,char* remote_host,int remote_port ,bool &iFlag)  
  44. {      
  45.       
  46.     int iRet = 0;  
  47.     int i = 0;  
  48.     string  remote_ip = remote_host;  
  49.     struct sockaddr_in  remote_addr;  
  50.     remote_addr.sin_family = AF_INET;  
  51.     remote_addr.sin_addr.S_un.S_addr = inet_addr(remote_ip.c_str());  
  52.     remote_addr.sin_port = htons(remote_port);     
  53.   
  54.       
  55.       // 尝试去连接服务端    
  56.       iRet = connect(sockClient,(struct sockaddr *)&remote_addr,sizeof(SOCKADDR));  
  57.       if (0 == iRet)    
  58.       {    
  59.           return 0 ; // 连接成功    
  60.       }    
  61.       else if (iRet < 0 && GetLastError() == 10035) //errno == EINPROGRESS表示正在建立链接  
  62.       {    
  63.           fd_set fd;  
  64.           timeval tiout;  
  65.           tiout.tv_sec = 1;  
  66.           tiout.tv_usec = 0;  
  67.           for (i = 0; (i < 3) && (!iFlag); i++)//iFlag 即bexit时退出,防止在此循环中等待时间过长  
  68.           {  
  69.               FD_ZERO(&fd);    
  70.               FD_SET(sockClient, &fd); //相反的是FD_CLR(sockClient, &fd)   
  71.   
  72.               iRet = select(sockClient+1,NULL,&fd,NULL,&tiout);  
  73.               if (iRet <= 0)    
  74.               {    
  75.                   continue// 有错误(select错误或者超时)    
  76.               }    
  77.               //将检测到sockClient读事件或写时间,并不能说明connect成功  
  78.               if(FD_ISSET(sockClient,&fd))  
  79.               {     
  80.                   int error = -1;    
  81.                   int optLen = sizeof(int);    
  82.   
  83.                   if(getsockopt(sockClient, SOL_SOCKET, SO_ERROR, (char*)&error, &optLen) < 0)  
  84.                   {  
  85.                       continue//建立失败close(sockClient)  
  86.                   }  
  87.                   if (0 != error)    
  88.                   {    
  89.                       continue// 有错误    
  90.                   }    
  91.                   else    
  92.                   {  
  93.                       return 0;  // 无错误    
  94.                   }    
  95.               }        
  96.           }    
  97.        }  
  98.       else  
  99.       {  
  100.          return -1;;//出现错误   
  101.       }  
  102.     return -1;  
  103. }  
  104.   
  105. static int tcp_receive(SOCKET sockClient, char *pOut,int len ,bool &iFlag)  
  106. {  
  107.     int iRet = 0;  
  108.     int i = 0;  
  109.       
  110.     fd_set fd;  
  111.     timeval tiout;  
  112.     tiout.tv_sec = 1;  
  113.     tiout.tv_usec = 0;  
  114.   
  115.     for (i = 0; (i < 3) && (!iFlag); i++)//iFlag 即bexit时退出,防止在此循环中等待事件过长  
  116.     {  
  117.         FD_ZERO(&fd);  
  118.         FD_SET(sockClient, &fd);  
  119.         iRet = select(sockClient+1,&fd,NULL,NULL,&tiout);  
  120.           
  121.         if (iRet > 0  && FD_ISSET(sockClient,&fd))  
  122.         {  
  123.             return recv(sockClient, pOut, len, 0);  
  124.         }  
  125.         else // 无论出错超时还是暂时没有等到,都尝试3次  
  126.         {  
  127.             continue;  
  128.         }  
  129.           
  130.     }  
  131.       
  132.     return -1;  
  133. }  

你可能感兴趣的:(网络通信)