9

Linux でのサーバー ソケットに問題があります。なんらかの理由でサーバー ソケットが消えBad file descriptor、受信接続を待機する select 呼び出しでエラーが発生します。この問題は、別のスレッドで無関係なソケット接続を閉じると常に発生します。これは、2.6.36 カーネルの組み込み Linux で発生します。

なぜこれが起こるのか誰にも分かりますか?サーバー ソケットが単純に消えてBad file descriptor.

編集: 他のソケット コードは VNC サーバーを実装し、完全に異なるスレッドで実行されます。その他のコードで唯一特別なのは の使用ですsetjmp/longjmpが、それは問題にはなりません。

サーバーソケットを作成するコードは次のとおりです。

int server_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

struct sockaddr_in saddr;
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
saddr.sin_port = htons(1234);

const int optionval = 1;
setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &optionval, sizeof(optionval));

if (bind(server_socket, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
    perror("bind");
    return 0;
}

if (listen(server_socket, 1) < 0) {
    perror("listen");
    return 0;
}

以下のコードを使用して着信接続を待ちます。

static int WaitForConnection(int server_socket, struct timeval *timeout)
{
    fd_set read_fds;

    FD_ZERO(&read_fds);
    int max_sd = server_socket;
    FD_SET(server_socket, &read_fds);

    // This select will result in 'EBADFD' in the error case.
    // Even though the server socket was not closed with 'close'.
    int res = select(max_sd + 1, &read_fds, NULL, NULL, timeout);
    if (res > 0) {
        struct sockaddr_in caddr;
        socklen_t clen = sizeof(caddr);
        return accept(server_socket, (struct sockaddr *) &caddr, &clen);
    }

    return -1;
}

編集: 問題が発生した場合、現在サーバーを再起動するだけですが、サーバーソケットIDが突然無効なファイル記述子になる理由がわかりません:

int error = 0;
socklen_t len = sizeof (error);
int retval = getsockopt (server_socket, SOL_SOCKET, SO_ERROR, &error, &len );
if (retval < 0) {
    close(server_socket);
    goto server_start;
}
4

4 に答える 4

6

ソケット (ファイル記述子) は、通常、.NET の生のポインタと同じ管理上の問題を抱えていますC-1ソケットを閉じるときはいつでも、記述子の値を保持する変数に割り当てることを忘れないでください。

close(socket);
socket = -1;

Cポインタに対して行うように

free(buffer);
buffer = NULL;

これを行うのを忘れた場合、後でソケットを 2 回閉じることができfree()ます。

もう 1 つの問題は、人々が通常忘れている事実に関連している可能性があります。UNIX 環境のファイル記述子は から始まり0ます。コードのどこかにある場合

struct FooData {
    int foo;
    int socket;
    ...
}

// Either
FooData my_data_1 = {0};
// Or
FooData my_data_2;
memset(&my_data_2, 0, sizeof(my_data_2));

どちらの場合も、有効な記述子 ( ) 値my_data_1を持っています。その後、構造の解放を担当するコードの一部が、この記述子をやみくもに使用する可能性があります。これは、たまたまサーバーのリッスン ソケット (my_data_2socketFooDataclose()0

于 2015-02-27T09:29:35.673 に答える
3

1-ソケットを閉じます:

close(sockfd);

2-選択セットからソケットファイル記述子をクリアします。

FD_CLR(sockfd,&master); //opposite of FD_SET
于 2015-10-09T09:19:15.833 に答える
1

コード内で 2 つのエラー ケースを区別しません。どちらも失敗するselectか、accept. 私の推測では、タイムアウトが発生しただけで、 select が返されます0

  • 印刷retvalerrnoelseブランチで
  • の戻り値をaccept別途調べる
  • 各システムコールの前にerrnoリセットされていることを確認してください0
于 2012-07-31T08:21:42.870 に答える
-3

Linux では、接続を作成して閉じた後、新しい接続を作成する前にしばらく待つ必要があります。Linux と同様に、ソケットはポート番号を解放しません。ソケットを閉じるとすぐに。

また

ソケットを再利用すると、不正なファイル記述子が必要になります。

于 2012-07-31T07:30:24.253 に答える