非阻塞connect的实现

步骤1: 设置非阻塞,启动连接

实现非阻塞 connect ,首先把 sockfd 设置成非阻塞的。这样调用

connect 可以立刻返回,根据返回值和 errno 处理三种情况:

(1) 如果返回 0,表示 connect 成功。

(2) 如果返回值小于 0, errno 为 EINPROGRESS,  表示连接

      建立已经启动但是尚未完成。这是期望的结果,不是真正的错误。

(3) 如果返回值小于0,errno 不是 EINPROGRESS,则连接出错了。

 

步骤2:判断可读和可写

然后把 sockfd 加入 select 的读写监听集合,通过 select 判断 sockfd

是否可写,处理三种情况:

(1) 如果连接建立好了,对方没有数据到达,那么 sockfd 是可写的

(2) 如果在 select 之前,连接就建立好了,而且对方的数据已到达,

      那么 sockfd 是可读和可写的。

(3) 如果连接发生错误,sockfd 也是可读和可写的。

判断 connect 是否成功,就得区别 (2) 和 (3),这两种情况下 sockfd 都是

可读和可写的,区分的方法是,调用 getsockopt 检查是否出错。

 

步骤3:使用 getsockopt 函数检查错误

getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len)

在 sockfd 都是可读和可写的情况下,我们使用 getsockopt 来检查连接

是否出错。但这里有一个可移植性的问题。

如果发生错误,getsockopt 源自 Berkeley 的实现将在变量 error 中

返回错误,getsockopt 本身返回0;然而 Solaris 却让 getsockopt 返回 -1,

并把错误保存在 errno 变量中。所以在判断是否有错误的时候,要处理

这两种情况。

 

代码:

 

C代码   收藏代码
  1. int conn_nonb(int sockfd, const struct sockaddr_in *saptr, socklen_t salen, int nsec)  
  2. {  
  3.     int flags, n, error, code;  
  4.     socklen_t len;  
  5.     fd_set wset;  
  6.     struct timeval tval;  
  7.   
  8.     flags = fcntl(sockfd, F_GETFL, 0);  
  9.     fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);  
  10.   
  11.     error = 0;  
  12.     if ((n == connect(sockfd, saptr, salen)) == 0) {  
  13.         goto done;  
  14.     } else if (n < 0 && errno != EINPROGRESS){  
  15.         return (-1);  
  16.     }  
  17.   
  18.     /* Do whatever we want while the connect is taking place */  
  19.   
  20.     FD_ZERO(&wset);  
  21.     FD_SET(sockfd, &wset);  
  22.     tval.tv_sec = nsec;  
  23.     tval.tv_usec = 0;  
  24.   
  25.     if ((n = select(sockfd+1, NULL, &wset,   
  26.                     NULL, nsec ? &tval : NULL)) == 0) {  
  27.         close(sockfd);  /* timeout */  
  28.         errno = ETIMEDOUT;  
  29.         return (-1);  
  30.     }  
  31.   
  32.     if (FD_ISSET(sockfd, &wset)) {  
  33.         len = sizeof(error);  
  34.         code = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len);  
  35.         /* 如果发生错误,Solaris实现的getsockopt返回-1, 
  36.          * 把pending error设置给errno. Berkeley实现的 
  37.          * getsockopt返回0, pending error返回给error.  
  38.          * 我们需要处理这两种情况 */  
  39.         if (code < 0 || error) {  
  40.             close(sockfd);  
  41.             if (error)   
  42.                 errno = error;  
  43.             return (-1);  
  44.         }  
  45.     } else {  
  46.         fprintf(stderr, "select error: sockfd not set");  
  47.         exit(0);  
  48.     }  
  49.   
  50. done:  
  51.     fcntl(sockfd, F_SETFL, flags);  /* restore file status flags */  
  52.     return (0);  
  53. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值