Home > Erlang探索, 网络编程 > 非阻塞connect的一个细节

非阻塞connect的一个细节

May 18th, 2010

原创文章,转载请注明: 转载自系统技术非业余研究

本文链接地址: 非阻塞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.

  1. hoterran
    May 18th, 2010 at 16:23 | #1

    非阻塞connect 都是这样的啊,返回值,error都要判断,没看到特殊之处

    Yu Feng Reply:

    我之前都没判断,所以觉得很多人不清楚,而且这个SO_ERROR不是每个平台都要这样!

  2. yoyo
    June 29th, 2010 at 18:15 | #2

    这个是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;
    }

  3. May 16th, 2011 at 18:55 | #3

    第三版,16章352页。。

Comments are closed.