1

UNIXネットワークプログラミングのStevensのconnect_nonb()を使用しています。

int
connect_nonb(int sockfd, const SA *saptr, socklen_t salen, int nsec)
{
    int                     flags, n, error;
    socklen_t               len;
    fd_set                  rset, wset;
    struct timeval  tval;

    flags = Fcntl(sockfd, F_GETFL, 0);
    Fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

    error = 0;
    if ( (n = connect(sockfd, saptr, salen)) < 0)
            if (errno != EINPROGRESS)
                    return(-1);

    /* Do whatever we want while the connect is taking place. */

    if (n == 0)
            goto done;      /* connect completed immediately */

    FD_ZERO(&rset);
    FD_SET(sockfd, &rset);
    wset = rset;
    tval.tv_sec = nsec;
    tval.tv_usec = 0;

    if ( (n = Select(sockfd+1, &rset, &wset, NULL,
                                     nsec ? &tval : NULL)) == 0) {
            close(sockfd);          /* timeout */
            errno = ETIMEDOUT;
            return(-1);
    }

    if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
            len = sizeof(error);
            if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
                    return(-1);                     /* Solaris pending error */
    } else
            err_quit("select error: sockfd not set");

done:
    Fcntl(sockfd, F_SETFL, flags);  /* restore file status flags */

    if (error) {
            close(sockfd);          /* just in case */
            errno = error;
            return(-1);
    }
    return(0);
}

この関数を使用すると、connect()のカスタムタイムアウトが可能になります。接続が成功するのを待っているselect()でブロックしているときに、シグナルが受信された場合、select()は-1(EINTR)で終了します。この時点で、select()タイムアウトは期限切れになっておらず、接続は成功していません(つまり、ターゲットホストが切断されている可能性があります)が、後続のgetsockopt()はエラーを返しません。

Getsockopt()はエラーを返す必要がありますか、それともStevensコードはselect()の戻りコード(およびerrno)をチェックする必要がありますか?

現在、存在しないホストに接続し、シグナルがselect()に割り込むと、この関数は誤って成功を返します。

4

1 に答える 1

2

何なのかわかりませんSelect()。ある種の薄いラッパーだと思いますselect()

ほとんどのアプリケーションでは、でselect()失敗するたびにEINTR、サイレントループを実行してselect()再度呼び出す必要があります。おそらく、タイムアウトを再計算して、の前の呼び出しで時間が経過したことを考慮した後select()です。

この場合も例外ではありません。select()ループ内にある必要があります。

于 2013-02-20T18:55:44.810 に答える