1

プロセス間通信のために2つのスレッド間で通信するためにドメインソケット(AF_UNIX)を使用しています。これはlibevでうまく機能するように選択されています。ドメインソケットのrecv側で使用します。これは、送信するデータが一定の4864バイトであることを除いて、非常にうまく機能します。このデータを断片化する余裕はありません。私はいつもドメインソケットはデータを断片化しないと思っていましたが、結局のところ、断片化しています。スレッド間の通信がピークに達すると、次のことがわかります。

Thread 1:
SEND = 4864 actual size = 4864

Thread 2:
READ = 3328 actual size = 4864

Thread 1:
SEND = 4864 actual size = 4864

Thread 2:
READ = 1536 actual size = 4864

ご覧のとおり、スレッド2はデータをフラグメント(3328 + 1536)で受信しました。これは私のアプリケーションにとって本当に悪いことです。とにかくそれを断片化しないようにすることができますか?IP_DONTFRAGはAF_INETファミリにのみ設定できることを理解していますか?誰かが代替案を提案できますか?

更新:sendtoコード

ssize_t
socket_domain_writer_dgram_send(int *domain_sd, domain_packet_t *pkt) {

    struct sockaddr_un remote;
    unsigned long len = 0;
    ssize_t ret = 0;

    memset(&remote, '\0', sizeof(struct sockaddr_un));
    remote.sun_family = AF_UNIX;
    strncpy(remote.sun_path, DOMAIN_SOCK_PATH, strlen(DOMAIN_SOCK_PATH));
    len  = strlen(remote.sun_path) + sizeof(remote.sun_family) + 1;

    ret = sendto(*domain_sd, pkt, sizeof(*pkt), 0, (struct sockaddr *)&remote, sizeof(struct sockaddr_un));
    if (ret == -1) {
        bps_log(BPS_LOGGER_RD, ASL_LEVEL_ERR, "Domain writer could not connect send packets", errno);
    }
    return ret;
}
4

2 に答える 2

2

4864 + 3328 = 8192。私の推測では、場合によっては2つの4864バイトのパケットを連続して送信していて、どこかで8KBのカーネルバッファがいっぱいになっていると思います。IP_DONTFRAGここではIPが関与していないため、適用できません。表示されている「断片化」は、まったく異なるメカニズムを介して発生しています。

送信するすべてのデータがパケットで構成されている場合はSOCK_DGRAM、ストリームの代わりにデータグラムソケット()を使用することをお勧めします。これsend()により、部分的なライトスルーを許可するのではなく、カーネルバッファにパケット全体を格納するのに十分なスペースがない場合にブロックが作成され、それぞれrecv()が正確に1つのパケットを返すため、フレーミングを処理する必要はありません。

于 2013-03-18T23:52:48.543 に答える
2

SOCK_STREAMは、定義上、メッセージ境界を保持しません。SOCK_DGRAMまたはSOCK_SEQPACKETを使用して再試行してください。

http://man7.org/linux/man-pages/man7/unix.7.html

一方、アーキテクチャのページサイズよりも大きいメッセージを渡す可能性があることを考慮してください。たとえば、amd64の場合、メモリページは4Kです。それが何らかの理由で問題になる場合は、パケットを2つに分割することが理にかなっている可能性があります。

ただし、これはパケットが断片化されて到着するための実際の問題ではないことに注意してください。ソケットの受信側にパケットアセンブラがあるのが一般的です。それを実装することの何が問題になっていますか?

于 2013-03-19T00:08:44.717 に答える