当客户端进程(例如浏览器)需要同时发起多个连接的时候,如果使用阻塞connect,那么先发起第一个连接并等待它返回,然后第二个,第三……这样效率不高,在等待连接返回的时间内,可以做一些其他的任务处理。而且,如果某个连接因为超时才返回的话,那么客户端进程阻塞在这个连接上的时间将会更多。所以,这种情况下,我们更喜欢非阻塞connect。
在使用非阻塞connect的时候,有以下几点需要注意:
1、When a TCP socket is set to nonblocking and then connect is called, connect returns immediately with an error of EINPROGRESS but the TCP three-way handshake continues.
2、Even though the socket is nonblocking, if the server to which we are connecting is on the same host, the connection is normally established immediately when we call connect.
3、POSIX have the following two rules regarding select and nonblocking connects:(1) When the connection completes successfully, the descriptor becomes writable. (2) When the connection establishment encounters an error, the descriptor becomes both readable and writable.// 省略 select
FD_ISSET(sockfd, &wset)
{
int error = 0;
socklen_t error_len = sizeof(error);
int ret = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &error_len);
if(ret < 0)
{
printf("connection error: %s", strerror(errno));
return -1;
}
else
{
if(error != 0)
{
errno = error;
printf("connection error: %s", strerror(errno));
return -1;
}
else
{
printf("connection success");
return 0;
}
}
}
There are portability problems with various socket implementations and nonblocking connects. If an error occurred, Berkeley-derived implementations of getsockopt return 0 with the pending error returned in our variable error. But Solaris causes getsockopt itself to return –1 with errno set to the pending error.
对于一个阻塞的套接字,当我们调用connect时被信号中断了,它会返回EINTR错误。但是要注意,我们不能对这个套接字再次调用connect,否则将返回EADDRINUSE错误。此时正确的做法是调用select,就像使用非阻塞connect一样。select returns when the connection completes successfully (making the socket writable) or when the connection fails (making the socket readable and writable).