我们用man connection命令查看手册,如下:
 
  1. EINPROGRESS
  2. The socket is nonblocking and the connection cannot be completed immediately. It
  3. is possible to select(2) or poll(2) for completion by selecting the socket for
  4. writing. After select(2) indicates writability, use getsockopt(2) to read the
  5. SO_ERROR option at level SOL_SOCKET to determine whether connect() completed successfully (SO_ERROR is zero) or unsuccessfully (SO_ERROR is one of the usual error
  6. codes listed here, explaining the reason for the failure).
当connect可写时还可能是发生了错误,我们必须判断这种情况。发生错误时套接字既可读又可写,而connect连接成功时套接字也可能即可读又可写(select之前有可能连接已经建立并有来自对端的数据到达).
 
如何区分这两种情况呢?因此,必须调用

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

另一个问题,对于非阻塞式套接字,如果其上的connect调用被信号中断并且不会由内核自动重启,那么它将返回EINTR,此时我们不能再次调用connect等待未完成的连接继续完成,这样做将导致返回EADDRINUSE错误。我们只能调用select检测其状态,就像上面说的那样。

 
 
int connect_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds)
{
int ret;
socklen_t addrlen = sizeof(struct sockaddr_in); if (wait_seconds > 0)
activate_nonblock(fd); //设为非阻塞 ret = connect(fd, (struct sockaddr*)addr, addrlen);
if (ret < 0 && errno == EINPROGRESS)
{
//printf("11111111111111111111\n");
fd_set connect_fdset;
struct timeval timeout;
FD_ZERO(&connect_fdset);
FD_SET(fd, &connect_fdset);
timeout.tv_sec = wait_seconds;
timeout.tv_usec = 0;
do
{
// 一但连接建立,则套接字就可写 所以connect_fdset放在了写集合中
ret = select(fd + 1, NULL, &connect_fdset, NULL, &timeout);
} while (ret < 0 && errno == EINTR);
if (ret == 0)
{
ret = -1;
errno = ETIMEDOUT;
}
else if (ret < 0)
return -1;
else if (ret == 1)
{
//printf("22222222222222222\n");
/* ret返回为1(表示套接字可写),可能有两种情况,一种是连接建立成功,一种是套接字产生错误,*/
/* 此时错误信息不会保存至errno变量中,因此,需要调用getsockopt来获取。 */
int err;
socklen_t socklen = sizeof(err);
int sockoptret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &socklen);
if (sockoptret == -1)
{
return -1;
}
if (err == 0)
{
//printf("3333333333333\n");
ret = 0;
}
else
{
//printf("4444444444444444:%d\n", err);
errno = err;
ret = -1;
}
}
}
if (wait_seconds > 0)
{
deactivate_nonblock(fd); //设回阻塞
}
return ret;
}

  

关于非阻塞connect的若干细节性问题的更多相关文章

  1. TCP非阻塞accept和非阻塞connect

    http://blog.chinaunix.net/uid-20751538-id-238260.html 非阻塞accept     当一个已完成的连接准备好被accept的时候,select会把监 ...

  2. 面向连接的socket数据处理过程以及非阻塞connect问题

    对于面向连接的socket类型(SOCK_STREAM,SOCK_SEQPACKET)在读写数据之前必须建立连接,首先服务器端socket必须在一个客户端知道的地址进行监听,也就是创建socket之后 ...

  3. (转)非阻塞Connect对于select时应注意问题

    对于面向连接的socket类型(SOCK_STREAM,SOCK_SEQPACKET)在读写数据之前必须建立连接,首先服务器端socket必须在一个客户端知道的地址进行监听,也就是创建socket之后 ...

  4. UNIX网络编程——非阻塞connect:时间获取客户程序

    #include "unp.h" int connect_nonb(int sockfd, const SA *saptr, socklen_t salen, int nsec) ...

  5. UNIX网络编程——非阻塞connect

    当在一个非阻塞的TCP套接字上调用connect时,connect将立即返回一个EINPROGRESS错误,不过已经发起的TCP三次握手继续进行.我们接着使用select检测这个连接或成功或失败的已建 ...

  6. TCP之非阻塞connect和accept

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

  7. UNIX网络编程-非阻塞connect和非阻塞accept

    1.非阻塞connect 在看了很多资料之后,我自己的理解是:在socket发起一次连接的时候,这个过程需要一段时间来将三次握手的过程走完,如果在网络状况不好或者是其他的一些情况下,这个过程需要比较长 ...

  8. linux 客户端 Socket 非阻塞connect编程

    开发测试环境:虚拟机CentOS,windows网络调试助手        非阻塞模式有3种用途        1.三次握手同时做其他的处理.connect要花一个往返时间完成,从几毫秒的局域网到几百 ...

  9. 非阻塞connect

    步骤1: 设置非阻塞,启动连接 实现非阻塞 connect ,首先把 sockfd 设置成非阻塞的.这样调用 connect 可以立刻返回,根据返回值和 errno 处理三种情况: () 如果返回 , ...

随机推荐

  1. SVM神经网络的术语理解

    SVM(Support Vector Machine)翻译成中文是支持向量机, 这里的“机(machine,机器)”实际上是一个算法.而支持向量则是指那些在间隔区边缘的训练样本点[1]. 当初看到这个 ...

  2. 面向对象之virtual

    1.父类声明一个虚方法,子类可以对其进行重写(也可以不重写) 2.虚方法必须有方法体,抽象方法必须没有方法体 3.虚方法可以出现在抽象类中,抽象方法必须出现在抽象类中

  3. eclipse Maven -->web project

    http://blog.chinaunix.net/uid-26959955-id-3248053.html http://blog.csdn.net/wilsonke/article/details ...

  4. JS中数组对象去重

    JS数组去重 JS中对数组去重最好不要用unique方法,该方法主要是对dom节点数组的去重,如果对普通的数组元素去重只会去掉与之相邻的重复元素,也就是如果数组中还有不相邻的重复元素存在,将不会被去掉 ...

  5. 窗口类型(Widget, Window, Dialog, Desktop, SubWindow等等)

    http://doc.qt.io/qt-5/qwidget.html#windowFlags-prop http://doc.qt.io/qt-5/qtwidgets-widgets-windowfl ...

  6. the differences between function and procedure

    一.自定义函数: 1. 可以返回表变量 2. 限制颇多,包括 不能使用output参数: 不能用临时表: 函数内部的操作不能影响到外部环境: 不能通过select返回结果集: 不能update,del ...

  7. 默认的app.js

    我们通过npm start 默认入口是app.js,如果想默认入口改为main.js,可以修改项目下的/bin/www文件把app修改main var app = require('../app');

  8. windows bat常用命令积累

    1.判断文件夹是否为空  dir/a/b "D:\test"|findstr . >nul&&(echo 有文件)||(echo 空)   2.多层文件夹遍历 ...

  9. ajax处理回调函数,用ajax向后台发送数据

    这是我的后台返回给前台的数据: 处理后台返回的数据有一下两种方式: function sethouse_housing_pattern(housing_pattern){ var str=[]; va ...

  10. cf708B. Recover the String---(构造法)

    题目链接:http://codeforces.com/problemset/problem/708/B 意思是给出四个参数 a00表01串中00对的数量 a01表01串中01对的数量 a10表01串中 ...