1

私はこのような機能を持っています:

static int
rcv_kern(int sock, void *buf, int len, struct sockaddr *addr,
     socklen_t *addrlen)
{
    struct timeval timeout = {1, 0};
    fd_set set;
    int status;

    FD_SET(sock, &set);
    if ((status = select(sock + 1, &set, NULL, NULL, &timeout)) == 0) {
        FD_ZERO(&set);
        fprintf(stderr, 
            "timeout while receiving answer from kernel\n");
        exit(1);
    } else if (status == -1) {
        FD_ZERO(&set);
        perror("recvfrom failed");
        exit(1);
    }
    FD_ZERO(&set);
    return recvfrom(sock, buf, len, 0, addr, addrlen);
}

これは、netlink を使用してカーネル空間からメッセージを受信するために使用されます。しかし、実行すると、ソースコードから「カーネルからの応答を受信中にタイムアウトしました」というメッセージが常に表示されます。これは、「選択」メソッドが常に「0」を返すためです。理由がわかりません。どなたかアドバイスをいただければ幸いです。

4

5 に答える 5

2

次のように関数を書き直す必要があります。

static int
rcv_kern(int sock, void *buf, int len, struct sockaddr *addr,
     socklen_t *addrlen)
{
    struct timeval timeout = {1, 0};
    fd_set set;
    int status;

    FD_ZERO(&set);
    FD_SET(sock, &set);
    if ((status = select(sock + 1, &set, NULL, NULL, &timeout)) == 0) {
        fprintf(stderr, 
                "timeout while receiving answer from kernel\n");
        exit(1);
    } else if (status < 0) {
        perror("recvfrom failed");
        exit(1);
    }
    if ((status = recvfrom(sock, buf, len, 0, addr, addrlen)) < 0) {
        perror("recvfrom error");
        exit(1);
    }
    if (status == 0) {
        fprintf(stderr, "kernel closed socket\n");
        exit(1);
    }
    return status;
}

他の誰かが言ったように、select を呼び出す前に FD_ZERO を呼び出す必要があります。FD_ZERO への他の呼び出しは不要です。また、完全なエラー チェックを行う必要があります。

于 2009-06-17T10:40:14.977 に答える
1

タイムアウトとは関係ありませんが、FD_SET(sock, &set) の前に FD_ZERO(&set) を実行する必要があります。そうしないと、fd_set が初期化されず、多くのセット ビットが含まれる可能性があります。また、終了する前の FD_ZERO() はかなり無意味です。

于 2009-05-05T02:16:05.353 に答える
0

手始めに、タイムアウトが発生したときに実際のエラーが何であったかを調べることができますstrerror(errno)(errno を印刷することも賢明です)。

errno がない場合に何が問題であるかを推測することに関しては、読み取るものがあるという保証はないことに注意してください。accept(2) を介してソケットを取得したとしても、セットアップされた接続である可能性がありますが、クライアントは書き込みに失敗しました。通常、select(2) を 1 つだけ実行することはありません。プログラムが終了するまでselect(2)を呼び出し続ける単一のメインループが必要です。これは、タイムアウトがほぼいつでも何らかの理由で発生する可能性があるためです。

その他の考えられる問題:

  • クライアントが接続できません。
  • ソケットを正しくバインドできていません。
  • bind(2) を呼び出した後、サーバーのソケットで listen(2) を呼び出すのを忘れています。

IP ソケットを使用している場合は、Wireshark を使用してネットワーク トラフィックを調べ、クライアントが期待どおりに動作しているかどうかを確認できます。

于 2009-05-05T03:02:14.913 に答える
0

カーネル空間でコードを調査しましたが、カーネルが「skb_dequeue(&sk->sk_receive_queue)」メソッドを使用してクライアントからメッセージを受信できないことがわかっています。私はそれがどのように起こるかわかりません。

于 2009-05-05T02:17:28.000 に答える