非阻塞connect的一个细节
原创文章,转载请注明: 转载自系统技术非业余研究
本文链接地址: 非阻塞connect的一个细节
昨天听zhuzhaoyuan说的一个connect细节. 通常我们connect的时候都是非阻塞的, 在connect调用后把句柄挂到poll去, 等poll通知可写的时候, 我们就认为connect成功了. 但是在linux平台下实际上不一定成功, 具体的要用socket get_opt来检查下出错码来决定.
以下是从man 2 connnect摘抄的:
EINPROGRESS
The socket(2,7,n) is non-blocking and the connection cannot be com-
pleted immediately. It is possible to select(2,7,2 select_tut)(2) or poll(2) for
completion by selecting the socket(2,7,n) for writing. After select(2,7,2 select_tut)
indicates writability, use getsockopt(2) to read(2,n,1 builtins) the SO_ERROR
option at level SOL_SOCKET to determine whether connect com-
pleted successfully (SO_ERROR is zero) or unsuccessfully
(SO_ERROR is one of the usual error(8,n) codes listed here, explain-
ing the reason for the failure).
我们看下erlang的inet_drv是如何处理的.
./erts/emulator/drivers/common/inet_drv.c:
{ int error = 0; /* Has to be initiated, we check it */ unsigned int sz = sizeof(error); /* even if we get -1 */ int code = sock_getopt(desc->inet.s, SOL_SOCKET, SO_ERROR, (void *)&error, &sz); if ((code < 0) || error) { desc->inet.state = TCP_STATE_BOUND; /* restore state */ ret = async_error(INETP(desc), error); goto done; } }
结论: 细节决定品质.
Post Footer automatically generated by wp-posturl plugin for wordpress.
非阻塞connect 都是这样的啊,返回值,error都要判断,没看到特殊之处
Yu Feng Reply:
May 18th, 2010 at 5:21 pm
我之前都没判断,所以觉得很多人不清楚,而且这个SO_ERROR不是每个平台都要这样!
这个是APR的写法
int rc;
do {
rc = connect(sock->socketdes,
(const struct sockaddr *)&sa->sa.sin,
sa->salen);
} while (rc == -1 && errno == EINTR);
/* we can see EINPROGRESS the first time connect is called on a non-blocking
* socket; if called again, we can see EALREADY
*/
if ((rc == -1) && (errno == EINPROGRESS || errno == EALREADY)
&& (sock->timeout > 0)) {
rc = apr_wait_for_io_or_timeout(NULL, sock, 0); /** USE SELECT TO WAIT TIMEOUT **/
if (rc != APR_SUCCESS) {
return rc;
}
#ifdef SO_ERROR
{
int error;
apr_socklen_t len = sizeof(error);
if ((rc = getsockopt(sock->socketdes, SOL_SOCKET, SO_ERROR,
(char *)&error, &len)) < 0) {
return errno;
}
if (error) {
return error;
}
}
#endif /* SO_ERROR */
}
if (rc == -1 && errno != EISCONN) {
return errno;
}
第三版,16章352页。。