首先來看一段代碼,該代碼摘自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處理是否有什么不同。