首先来看一段代码,该代码摘自http://www.cnblogs.com/yuxingfirst/archive/2013/03/08/2950281.html,感谢这位网友
int select_version(int *fd) {
int c_fd = *fd;
fd_set rset, wset;
struct timeval tval;
FD_ZERO(&rset);
FD_SET(c_fd, &rset);
wset = rset;
tval.tv_sec = 0;
tval.tv_usec = 300 * 1000; //300毫秒
int ready_n;
if ((ready_n = select(c_fd + 1, &rset, &wset, NULL, &tval)) == 0) {
close(c_fd); /* timeout */
errno = ETIMEDOUT;
perror("select timeout.\n");
return (-1);
}
if (FD_ISSET(c_fd, &rset)) {
int error;
socklen_t len = sizeof (error);
// 这里没出错,所以errno值没有改变
if (getsockopt(c_fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
cout << "getsockopt error." << endl;
return -1;
}
cout << "in fire." << error << endl;
}
if (FD_ISSET(c_fd, &wset)) {
int error;
socklen_t len = sizeof (error);
if (getsockopt(c_fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
cout << "getsockopt error." << endl;
return -1;
}
cout << "out fire." << error << endl;
}
return 0;
}
这段代码主要处理的是在connect返回EINPROGRESS的情况下,在select中的连接成功的处理。
网上的结论是:
Posix 定义了两条与 select 和 非阻塞 connect 相关的规定:1)连接成功建立时,socket 描述字变为可写。(连接建立时,写缓冲区空闲,所以可写)2)连接建立失败时,socket 描述字既可读又可写。 (由于有未决的错误,从而可读又可写)
随便测试一个不可用端口,上面的代码依然返回0,可见上面的代码有点问题,在判断FD_ISSET的时候,应该判断error是否大于0,应该这么写
if (FD_ISSET(c_fd, &rset)) {
int error;
socklen_t len = sizeof (error);
// 这里没出错,所以errno值没有改变
if (getsockopt(c_fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
cout << "getsockopt error." << endl;
return -1;
}
cout << "in fire." << error << endl;
if (error > 0) // 等于EINPROGRESS怎么办?
{
return -1;
}
}
这里面还有个问题就是如果这个时候error大于0但是等于EINPROGRESS是否算连接成功。
本例在linux2.6下测试没问题,不知道在windows或是在mac os上对于非阻塞的connect处理是否有什么不同。