web-dev-qa-db-ja.com

TCPソケット接続には「キープアライブ」がありますか?

HTTPキープアライブについて聞いたことがありますが、今のところ、リモートサーバーとのソケット接続を開きたいと思います。
このソケット接続はいつまでも開いたままになりますか、それともHTTPキープアライブに似たタイムアウト制限が関連付けられていますか?

76
Kevin Boyd

TCPソケットは、閉じられるまで開いたままです。

とはいえ、実際にデータを送信せずに接続の切断(ルーターのように壊れたなど)を検出することは非常に難しいため、ほとんどのアプリケーションは、確認するためにある種のping/pong反応を頻繁に実行します接続はまだ実際に生きています。

66

これで、このソケット接続は永久に開いたままになりますか、それともHTTPキープアライブに似たタイムアウト制限が関連付けられていますか?

簡単な答えは、yes、タイムアウトがあり、TCP Keep-Alive。

キープアライブタイムアウトを設定する場合は、以下の「TCPタイムアウト)の変更」セクションを参照してください。

前書き

TCP接続は、接続の両端に1つずつある2つのソケットで構成されます。片側が接続を終了する場合、相手側が確認するRSTパケットを送信し、両方がソケットを閉じます。

ただし、それが発生するまで、両側はソケットを無期限に開いたままにします。これにより、一方の側がRSTを介して他方に通知せずに、意図的にまたは何らかのエラーによりソケットを閉じる可能性が残ります。このシナリオを検出し、古い接続を閉じるために、TCP Keep Aliveプロセスが使用されます。

キープアライブプロセス

キープアライブの動作を決定する3つの構成可能なプロパティがあります。 Linuxでは1

  • tcp_keepalive_time
    • デフォルトは7200秒
  • tcp_keepalive_probes
    • デフォルト9
  • tcp_keepalive_intvl
    • デフォルト75秒

プロセスは次のように機能します。

  1. クライアントが開くTCP=接続
  2. 接続がtcp_keepalive_time秒間サイレントである場合、単一の空のACKパケットを送信します。1
  3. サーバーは、対応するACKで応答しましたか?
    • いいえ
      1. tcp_keepalive_intvl秒待ってから、別のACKを送信します
      2. 送信されたACKプローブの数がtcp_keepalive_probesと等しくなるまで繰り返します。
      3. この時点で応答が受信されていない場合は、RSTを送信して接続を終了します。
    • はい:ステップ2に戻る

このプロセスは、ほとんどのオペレーティングシステムでデフォルトで有効になっているため、もう一方の端が2時間11分(7200秒+ 75 * 9秒)応答しなくなると、デッドTCP接続は定期的に整理されます。

落とし穴

2時間のデフォルト

デフォルトでは、接続が2時間アイドルになるまでプロセスが開始されないため、古いTCP接続はプルーニングされる前に非常に長く残ることがあります。これは、高価な接続にとって特に有害です。データベース接続など。

キープアライブはオプションです

RFC 1122 4.2.3.6 によると、応答および/または中継TCP Keep-Aliveパケットはオプションです):

実装者は、TCP実装に「キープアライブ」を含めることができます。ただし、この方法は一般的に受け入れられていません。キープアライブが含まれている場合、アプリケーションはそれぞれに対してオンまたはオフにできる必要がありますTCP接続。デフォルトではオフになっている必要があります。

...

データを含まないACKセグメントは、TCPによって確実に送信されないことを覚えておくことが非常に重要です。

Keep-Aliveパケットにはデータが含まれておらず、厳密に必要ではないため、過度に使用するとインターウェブのチューブが詰まる危険性があります。

しかし、実際には、私の経験では、帯域幅が安くなるにつれて、この懸念は徐々に減少しているということです。したがって、キープアライブパケットは通常ドロップされません。 Amazon EC2ドキュメント たとえば、Keep-Aliveを間接的に支持しているため、AWSでホストしている場合は、Keep-Aliveに頼る方が安全かもしれませんが、走行距離は異なる場合があります。

TCPタイムアウトの変更

ソケットごと

残念ながらTCP接続はOSレベルで管理されているため、JavaはJava.net.Socketなどのソケットごとのタイムアウトの設定をサポートしていません。私はいくつかの試みを見つけました3 Java Native Interface(JNI)を使用してJavaこれらのオプションを設定するためにネイティブコードを呼び出すソケットがありますが、コミュニティで広く採用またはサポートされているものはありません。

代わりに、オペレーティングシステム全体に構成を適用するよう強制される場合があります。この構成は、システム全体で実行されているすべてのTCP接続に影響することに注意してください。

Linux

現在設定されているTCP Keep-Alive設定は

  • /proc/sys/net/ipv4/tcp_keepalive_time
  • /proc/sys/net/ipv4/tcp_keepalive_probes
  • /proc/sys/net/ipv4/tcp_keepalive_intvl

次のいずれかを更新できます。

# Send first Keep-Alive packet when a TCP socket has been idle for 3 minutes
$ echo 180 > /proc/sys/net/ipv4/tcp_keepalive_time
# Send three Keep-Alive probes...
$ echo 3 > /proc/sys/net/ipv4/tcp_keepalive_probes
# ... spaced 10 seconds apart.
$ echo 10 > /proc/sys/net/ipv4/tcp_keepalive_intvl

このような変更は、再起動しても持続しません。永続的な変更を行うには、sysctlを使用します。

sysctl -w net.ipv4.tcp_keepalive_time=180 net.ipv4.tcp_keepalive_probes=3 net.ipv4.tcp_keepalive_intvl=10

Mac OS X

現在構成されている設定は、sysctlで表示できます。

$ sysctl net.inet.tcp | grep -E "keepidle|keepintvl|keepcnt"
net.inet.tcp.keepidle: 7200000
net.inet.tcp.keepintvl: 75000
net.inet.tcp.keepcnt: 8

注目すべきは、Mac OS Xはkeepidlekeepintvlをミリ秒単位で定義するのに対し、Linuxは秒を使用するのとは対照的です。

プロパティはsysctlで設定でき、再起動後もこれらの設定が保持されます:

sysctl -w net.inet.tcp.keepidle=180000 net.inet.tcp.keepcnt=3 net.inet.tcp.keepintvl=10000

または、/etc/sysctl.confに追加することもできます(ファイルが存在しない場合は作成します)。

$ cat /etc/sysctl.conf
net.inet.tcp.keepidle=180000
net.inet.tcp.keepintvl=10000
net.inet.tcp.keepcnt=3

確認するWindowsマシンはありませんが、それぞれのTCP Keep-Alive設定を以下のレジストリで見つける必要があります。

\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters

脚注

1.詳細については、man tcpを参照してください。

2.このパケットは「キープアライブ」パケットと呼ばれることがよくありますが、TCP仕様内では通常のACKパケットです。Wiresharkなどのアプリケーションはソケット上の先行する通信に関して含まれているシーケンスと確認応答番号のメタ分析により、「キープアライブ」パケットとしてラベル付けします。

3.基本的なGoogle検索で見つかったいくつかの例は、 lucwilliams/JavaLinuxNet および flonatel/libdontdie です。

78
Cory Klein

SO_KEEPALIVEソケットオプションを探しています。

Java Socket API は、setKeepAliveメソッドとgetKeepAliveメソッドを介してアプリケーションに「キープアライブ」を公開します。

編集:SO_KEEPALIVEは、「実際の」データを送信せずにOSネットワークプロトコルスタックに実装されます。キープアライブ間隔はオペレーティングシステムに依存し、カーネルパラメーターを介して調整可能です。

データが送信されないため、SO_KEEPALIVEは、ネットワーク接続の活性度のみをテストでき、ソケットが接続されているサービスの活性度はテストできません。後者をテストするには、サーバーにメッセージを送信して応答を取得することを伴うものを実装する必要があります。

53
Stephen C

TCPキープアライブとHTTPキープアライブは非常に異なる概念です。 TCPでは、キープアライブは、古い接続を検出するために送信される管理パケットです。 HTTPでは、キープアライブは永続的な接続状態を意味します。

これは、TCP仕様、

キープアライブパケットは、一定時間内に接続に対してデータパケットまたは確認パケットが受信されなかった場合にのみ送信する必要があります。この間隔は設定可能でなければならず、デフォルトは2時間以上です

ご覧のとおり、デフォルトのTCPキープアライブ間隔はほとんどのアプリケーションにとって長すぎます。アプリケーションプロトコルにキープアライブを追加する必要がある場合があります。

33
ZZ Coder

マスカレードの背後にいる場合、NAT(ほとんどのホームユーザーは最近のように)、外部ポートの限られたプールがあり、これらはTCP接続。したがって、マスカレードNATは、一定期間データが送信されなかった場合に接続が終了したと想定する傾向があります。

この問題およびその他の問題(2つのエンドポイント間の任意の場所)は、合理的なアイドル期間の後にデータを送信しようとすると、接続が「機能しない」ことを意味します。ただし、データを送信するためにtryになるまでこれを発見できない場合があります。

キープアライブの両方を使用するreduces回線のどこかで接続が中断される可能性があり、接続が切断されたことをより早く見つけることもできます。

23
Artelius

以下に、キープアライブに関する補足資料を示します。

http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO

Javaでは実際のキープアライブ時間を制御できないため、Linuxカーネル(またはprocベースのOS)を使用している場合は例を使用して変更できます。

4
Jeach

In Java Socket – TCP接続はOSレベルで管理されます。Java.net.Socketは、キープアライブパケットのタイムアウトを設定するための組み込み関数を提供しません。ただし、Javaソケットのキープアライブオプションを有効にすることはできますが、デフォルトでは2時間11分(7200秒)かかります。古いTCP接続の後に処理されます。パージの前に非常に長い間利用できるため、これらのオプションを設定するためにネイティブコード(c ++)を呼び出すJava Native Interface(JNI)を使用するソリューションが見つかりました。

**** Windows OS ****

Windowsオペレーティングシステムでは、keepalive_timeとkeepalive_intvlは設定可能ですが、tcp_keepalive_probesは変更できません。デフォルトでは、TCPソケットが初期化されると、キープアライブタイムアウトが2時間に設定され、キープアライブ間隔が1秒キープアライブタイムアウトのデフォルトのシステム全体の値は、ミリ秒単位の値をとるKeepAliveTimeレジストリ設定を介して制御可能です。

Windows Vista以降では、キープアライブプローブ(データ再送信)の数は10に設定されており、変更できません。

Windows Server 2003、Windows XP、およびWindows 2000では、キープアライブプローブの数のデフォルト設定は5です。キープアライブプローブの数は制御可能です。 Windowsでは、Winsock IOCTLライブラリを使用してtcp-keepaliveパラメーターを構成します。

int WSAIoctl(SocketFD、//ソケットを識別する記述子SIO_KEEPALIVE_VALS、// dwIoControlCode(LPVOID)lpvInBuffer、// tcp_keepalive構造体へのポインタ(DWORD)cbInBuffer、//入力バッファの長さNULL、//出力バッファ0、 //出力バッファのサイズ(LPDWORD)lpcbBytesReturned、//返されたバイト数NULL、// OVERLAPPED構造体NULL //完了ルーチン);

Linux OS

Linuxにはキープアライブのサポートが組み込まれています。キープアライブを使用するには、TCP/IPネットワークを有効にする必要があります。プログラムは、setsockoptインターフェイスを使用して、ソケットのキープアライブ制御を要求する必要があります。

int setsockopt(int socket、int level、int optname、const void * optval、socklen_t optlen)

各クライアントソケットは、Java.net.Socketを使用して作成されます。各ソケットのファイル記述子IDは、Javaリフレクションを使用して取得します。

0

Windowsの場合 Microsoft docs

  • KeepAliveTime(REG_DWORD、ミリ秒、デフォルトでは7,200,000,000 = 2時間を意味するように設定されていません)-tcp_keepalive_timeに類似
  • KeepAliveInterval(REG_DWORD、ミリ秒、デフォルトでは1,000 = 1秒を意味するように設定されていません)-tcp_keepalive_intvlに類似
  • Windows Vistaではtcp_keepalive_probesに類似していないため、値は10に固定されており、変更できません
0
semen