Delayed ACK
Home >> Note >> Delayed ACK

遅延ACKオプションに関するメモ

研究に関連する実験で,遅延ACK(Delayed ACK)オプションを無効にした状態で, データ通信をする必要があったのですが,その時に陥ってしまった事例.

今まではFreeBSDのPCで実験を行っていたため,sysctlで簡単に無効にすることができたのですが, どうやらLinux系ではその方法では無効にできないようです.そこで, JM Projectで調べたところ,setsockopt()を用いてquickackモードを有効にすれば良い, という記述を発見したので,早速コードを修正してテストしてみたのですが・・・tcpdump で観察している限り,遅延ACKオプションは有効になったままの様子.

試行錯誤した結果,どうやら以下の記述が問題となっていたようです.

TCP_QUICKACK

・・・(中略)・・・

このフラグは永続的なものではなく、 quickack モードから/モードへ切り替えるためのものである。 これ以降の TCP プロトコルの動作によっては、内部のプロトコル処理や、 遅延 ack タイムアウトの発生、データ転送などの要因によって、 再び quickack から出たり入ったりする。 移植性の必要なプログラムではこのオプションを用いるべきではない。

setsockopt()でquickackモードに設定した後に何らかの条件で, システムが再び遅延ACKオプションを有効にしているようです. しかも性質の悪いことに,getsockopt()で確認してもquickackモードは有効 という結果が返ってきてしまいます.

結局,このときは以下のようにパケットを受信するたびにsetsockopt()でquickack モードを有効にする,という方法で逃げました.

if (FD_ISSET(fd, (fd_set*)&mask)) {
    bzero(buf, sizeof(buf));
    
    /* set quickack mode (forbidden delayed ACK) */
    setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, &qack, sizeof(qack));

    /* read packet (and throw away) */
    l = read(fd, buf, sizeof(buf));
    
    /* end of connection */
    if (l <= 0) break;
}

もう少しスマートな解決策はないものか.