SOCKET
       对于一个socket 是阻塞模式还是非阻塞模式的处理方法::

       方法:fcntl 设置;

                   即先用fcntl的F_GETFL获取flags,

                   用F_SETFL设置flags|O_NONBLOCK;        

                   (注意,取消非阻塞的方式是F_SETFL 设置flags&~O_NONBLOCK)

                   并在recv,send 时,将flag参数设置为MSG_DONTWAIT。

            

实现

fcntl 函数可以将一个socket 句柄设置成非阻塞模式: 
 | O_NONBLOCK);   //设置成非阻塞模式;
      flags  = fcntl(sockfd,F_GETFL,0);
&~O_NONBLOCK);    //设置成阻塞模式;
      并在recv,recvfrom和send,sendto数据时,将flag设置为MSG_DONTWAIT
      即:recv, send 函数的最后有一个flag 参数可以设置成MSG_DONTWAIT
      recv(sockfd, buff, buff_size,MSG_DONTWAIT);     //非阻塞模式的消息发送
      send(scokfd, buff, buff_size, MSG_DONTWAIT);   //非阻塞模式的消息接受
 设置之后每次的对于sockfd 的操作都是非阻塞的。
(
        connect   当返回0时,表示立即创建了socket链接,
                         当返回-1时,需要判断errno是否是EINPROGRESS(表示当前进程正在处理),否则失败
                         (                                     下面会有select或epoll监听fd是否建立链接,
select的例子:
    int ret = ::connect(_socket_fd, add.addr(), add.length());
     if(ret == 0)
     {
             //建立链接成功
     }
     else if(ret < 0 && errno == EINPROGRESS) //errno == EINPROGRESS表示正在建立链接
     {
           // 等待连接完成,errno == EINPROGRESS表示正在建立链接
          fd_set set;
          FD_ZERO(&set);
          FD_SET(_socket_fd,&set); 
 
          time_t = 10;          //(超时时间设置为10秒)
          struct timeval timeo;
          timeo.tv_sec = timeout / 1000; 
          timeo.tv_usec = (timeout % 1000) * 1000;           int retval = select(_socket_fd + 1, NULL, &set, NULL, &timeo);           //事件监听
           if(retval < 0)   
           {
                  //建立链接错误close(_socket_fd)
           }
           else if(retval == 0) // 超时
           {
                  //超时链接没有建立close(_socket_fd)
           }          //将检测到_socket_fd读事件或写时间,并不能说明connect成功
           if(FD_ISSET(_socket_fd,&set))
          {
                int error = 0;
                socklen_t len = sizeof(error);
                if(getsockopt(_socket_fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
                {
                        //建立简介失败close(_socket_fd)
                }
                if(error != 0) // 失败
                 {
                          //建立链接失败close(_socket_fd)
                 }
                 else
                 {
                          //建立链接成功
                 }
           }
     }
  else
  {
       //出现错误 close(_sock_fd)
  }epoll的例子:
     (//待续)
                                   当epoll或select监听到sockfd上有EPOLL_IN或EPOLL_OUT时,即读写事件时,
 并不能说明链接已经建立。
                                int error = 0;
                                 socklen_t ilen = sizeof(error);
                                 ret = getsockopt(fd,SOL_SOCKET,SO_ERROR,&error,&ilen);
                                 if(ret < 0)
                                 {
                                           //说明链接建立失败,close(fd);
                                }
                                 else if(error != 0 )
                                 {                                          //说明链接建立失败,close(fd);
                                 }                                else
                                {
 //说明链接建立成功。即可以向fd上写数据。
                                }
                        );  
 
 
 
当返回值为0时,表示对端已经关闭了这个链接,我们应该自己关闭这个链接,
                       即close(sockfd)。(因为异步操作会用select或epoll做事件触发,所以:)
                                   如果使用select,应该将sockfd清除掉,不再监听。
                                   如果使用epoll,系统会自己将sockfd清除掉,不再进行监听。
当返回值大于0 且 小于sizeof(buffer)时,表示数据肯定读完。(如果等于sizeof(buffer),可能有数据还没读,应该继续读,不可能有大于)
 当返回值小于0,即等于-1时:
                                     如果   errno   为  EAGAINE  或 EWOULDBLOCK                                      
                                     表示暂时无数据可读,可以继续读,或者等待epoll或select的后续通知。
                                     如果   errno   为  EINTR
                                     表示被中断了,可以继续读,或者等待epoll或select后续的通知。
。(此时应该close(sockfd))
                      (
发生EAGAINE,EWOULDBLOCK,EINTR错误时,
                         表明socket没有问题,即不用close(sockfd);
                         产生的原因:
                                 EAGAINE    和   EWOULDBLOCK  可能是多进程读同一个sockfd,可能一个进程读
                         到数据,其他进程就读取不到数据,当然单个进程也可能出现这种情况。
                         对于这种错误,不需用close(sockfd)。
                                可以等待select或epoll的下一次触发,继续读。
                      )
(recvfrom的判断也是一样的)
   send      返回值是实际发送的字符数。
 因为我们知道要发送的总长度,所以,如果没有发送完,我们可以继续发送。
                     当返回值为 -1   时, 我们需要判断  errno:
                         如果errno为  EAGAINE   或 EWOULDBLOCK ,表示当前缓冲区写满,可以继续写,或者等待epoll或select的后续通知。   
                         如果errno为EINTR  ,表示被终端了,可以继续写,或者等待epoll或select的后续通知。
                       (
发生EAGAINE,EWOULDBLOCK,EINTR错误时,
                         表明socket没有问题,即不用close(sockfd);
                         产生的原因:
                                 EAGAINE    和   EWOULDBLOCK  可能是多进程写同一个sockfd,可能一个进程写
                         了数据,其他进程就不能写数据,当然单个进程也可能出现这种情况。
                         对于这种错误,不需用close(sockfd)。
                                可以等待select或epoll的触发。
                      )
                        否则真的出错了,即errno不为EAGAINE或EWOULDBLOCK或EINTR,此时应该close(sockfd)
 (sendto的判断也是一样)
 
)