5

この質問は、 In a non-blocking socket connect, select() always returns 1 ;と非常に似ています (またはほとんど同じです) 。ただし、コードがどこで問題を起こしているのかを見つけることができないようです。

ノンブロッキング ソケットを使用しており、クライアントをサーバーに接続するときに select() を使用してタイムアウト/成功を確認したいと考えています。問題は、サーバーを実行していなくても、接続するものが何もない場合でも、 select() が常にほぼすぐに 1 を返すことです。助けてくれてありがとう、コードスニペットは次のとおりです。

//Loop through the addrinfo structs and try to connect to the first one we can
for(p = serverinfo; p != NULL; p = p->ai_next) {
    if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) 
    {
        //We couldn't create the socket, try again
        perror("client: socket");
        continue;
    }

    //Set the socket to non-blocking
    int flags = fcntl(sockfd, F_GETFL, 0);
    fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

    if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
        //The error was something other than non-block/in progress, try next addrinfo
        if(errno != EINPROGRESS) 
        {
            close(sockfd);
            perror("client: connect");
            continue;
        }

        fd_set write_fds;
        FD_ZERO(&write_fds);            //Zero out the file descriptor set
        FD_SET(sockfd, &write_fds);     //Set the current socket file descriptor into the set

        //We are going to use select to wait for the socket to connect
        struct timeval tv;              //Time value struct declaration
        tv.tv_sec = 5;                  //The second portion of the struct
        tv.tv_usec = 0;                 //The microsecond portion of the struct

        //DEBUG: This is ALWAYS 1
        int select_ret = select(sockfd + 1, NULL, &write_fds, NULL, &tv);
        cout << select_ret << endl;

        //Check return, -1 is error, 0 is timeout
        if(select_ret == -1 || select_ret == 0)
        {
            //We had an error connecting
            cout << "Error Connecting\n";
            close(sockfd);
            continue;
        }
    }

    //We successfully connected, break out of loop
    break;
}
4

2 に答える 2

4

select ()は何を返すと思いますか? select() は通常、複数のファイル記述子を待機するために使用されることを考慮してください.2つを接続している場合、 select の戻り値だけに基づいて、どれが成功/失敗したかをどのように知ることができますか? あなたはそうしないでしょう、明らかに。

そのため、 select() は、どのファイル記述子が何らかの方法で変更されたかを通知するだけであり、それが何であったかを個別に判断する必要があります。connect() の場合、getsockopt() を呼び出して接続試行の結果を取得する必要があります。非ブロッキング connect() の実行方法を説明しているこの回答を参照してください。

于 2012-07-01T22:34:57.383 に答える
1

ノンブロッキング モードで接続し、select() が接続が書き込み可能であることを示している場合は、connect() を再度呼び出す必要があります。これを行うと、errno == ECONNRESET またはそれが何であれ、-1 が返されます。

于 2012-07-01T22:29:46.730 に答える