Linux SO_KEEPALIVE属性、ハートビート


接続向けTCPソケットについては、実際のアプリケーションでは、対端が接続中であるかどうかを検出するのが一般的である.接続ポートは、1、接続が正常に閉じ、close()shutdown()接続が優雅に閉じられ、sendとrecvがすぐにエラーを返し、selectがSOCK_を返すERR; 2、接続の両端が異常に閉じて、例えばネットが切れて、突然電気が切れた.2つ目のケースでは、接続が切断されたかどうかを判断する方法はいくつかあります.1、自分でハートビートパッケージを作成します.簡単に言えば、自分のプログラムにスレッドを追加し、タイミングを決めて対端にパケットを送信し、ACKがあるかどうかを確認し、ACKの返却状況に応じて接続を管理します.この方法は比較的汎用的で、一般的に業務層の心拍数処理を使用し、柔軟に制御できるが、既存のプロトコルを変更した.2、TCPのkeepaliveメカニズムを使用し、UNIXネットワークプログラミングはSO_の使用を推奨しないKEEPALIVEは心拍数検査をします(なぜですか?).keepalive原理:TCPにはハートビートパケットが内蔵、サービス側を例にとる、serverが一定時間を超える(/proc/sys/net/ipv 4/tcp_keepalive_time 7200、すなわち2時間)データ伝送がないことを検出すると、client側にkeepalive packetが送信され、client側は3つの反応がある:1、client側が正常に接続され、1つのACKが戻る.サーバ側はACKを受け取るタイマーをリセットし、2時間後にプローブを送信する.2時間以内にデータ伝送が接続されている場合、その時間に基づいて2時間遅れてプローブパケットが送信される.2、クライアントが異常にシャットダウンしているか、ネットワークが切断されている.Clientは応答せず、serverはACKを受信できず、一定時間(/proc/sys/net/ipv 4/tcp_keepalive_intvl 75、75秒)後にkeepalive packetを再送し、一定回数(/proc/sys/net/ipv 4/tcp_keepalive_probes 9、すなわち9回)を再送する.3、クライアントはクラッシュしたが、再起動した.serverが受信したプローブ応答はリセットであり、server側は接続を終了する.
3つのパラメータのシステムデフォルト値を変更する一時的な方法:3つのファイルにパラメータを直接書き込み、システムの再起動に再設定が必要です.一時的な方法:sysctl-w net.ipv4.tcp_keepalive_intvl=20グローバル設定:変更可能/etc/sysctl.conf、加えて:net.ipv4.tcp_keepalive_intvl = 20 net.ipv4.tcp_keepalive_probes = 3 net.ipv4.tcp_keepalive_time = 60
 
/* Set TCP keep alive option to detect dead peers. The interval option
 * is only used for Linux as we are using Linux-specific APIs to set
 * the probe send time, interval, and count. */
int anetKeepAlive(char *err, int fd, int interval)
{
    int val = 1;
	//  keepalive  
    if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1)
    {
        anetSetError(err, "setsockopt SO_KEEPALIVE: %s", strerror(errno));
        return ANET_ERR;
    }

#ifdef __linux__
    /* Default settings are more or less garbage, with the keepalive time
     * set to 7200 by default on Linux. Modify settings to make the feature
     * actually useful. */

    /* Send first probe after interval. */
    val = interval;
    if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < 0) {
        anetSetError(err, "setsockopt TCP_KEEPIDLE: %s
", strerror(errno)); return ANET_ERR; } /* Send next probes after the specified interval. Note that we set the * delay as interval / 3, as we send three probes before detecting * an error (see the next setsockopt call). */ val = interval/3; if (val == 0) val = 1; if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) < 0) { anetSetError(err, "setsockopt TCP_KEEPINTVL: %s
", strerror(errno)); return ANET_ERR; } /* Consider the socket in error state after three we send three ACK * probes without getting a reply. */ val = 3; if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) { anetSetError(err, "setsockopt TCP_KEEPCNT: %s
", strerror(errno)); return ANET_ERR; } #endif return ANET_OK; }