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


84

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


1
「httpキープアライブ」が通常ソケットキープアライブに関連していないことを確認するために、接続を開いたままにしてさらに要求を行うHTTP /1.1機能について説明します。壊れたTCP接続を検出する必要があるため(または通常は限られた時間だけソケットを開いたままにする)、TCPキープアライブにのみ関連します。
eckes 2015年

回答:


72

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

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


4
いい考えだね。必ずしもそうする必要はありませんが、そうしないと、誰かが実際に何かをしたいと思うまで、壊れたリンクを検出できない可能性があります。あなたが実際に達成しようとしていることに応じて、どちらが良いことかもしれないし、そうでないかもしれない(あるいは問題になるかもしれないし、そうでないかもしれない)。
Matthew Scharley 2009

1
@Pacerier:完全にプロトコルに依存するため、プロトコルに依存しますが、1つのリテラル「PING」および「PONG」コマンドを必要とするテキストベースのプロトコルの場合はかなり一般的です。
Matthew Scharley 2012

4
@MatthewScharley:この「ピンポン」は、標準のTCP実装ですでに実装されており、「キープアライブ」と呼ばれます(この質問に対する他の一般的な回答を参照してください)。アプリレベルで実装する理由はありますか?
ティムクーパー

7
@TimCooper:そうではありません。他の回答へのコメントで強調したように、TCP実装はほとんどのアプリケーションレベルの要件には役立ちません。オンデマンドで送信することはできません。ほとんどのオペレーティングシステムでは、TCPキープアライブタイムアウトはシステム全体のレベルでのみ構成可能であり、アプリケーションに一般的に役立つには高すぎる設定になっています。
Matthew Scharley 2012年

13
@Timアプリケーションレベルでのキープアライブの理由は、TCP標準がキープアライブタイマーを2時間より長く設定することを推奨しているためです。今回存続するトラフィックのないTCP接続は見たことがありません。したがって、TCPキープアライブのものはデフォルトでは役に立ちません。
ロバート

96

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

短い答えはノー、それは永遠に開いたままにしません、それは数時間後にタイムアウトおそらくなります。したがって、はい、タイムアウトがありTCPキープアライブを介して強制されます

マシンでキープアライブタイムアウトを構成する場合は、以下の「TCPタイムアウトの変更」セクションを参照してください。それ以外の場合は、残りの回答を読んで、TCPキープアライブがどのように機能するかを確認してください。

前書き

TCP接続は、接続の両端に1つずつ、合計2つのソケットで構成されます。一方が接続を終了したい場合RST、もう一方が確認応答するパケットを送信し、両方がソケットを閉じます。

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

キープアライブプロセス

Keep-Alivesの動作を決定する3つの構成可能なプロパティがあります。Linuxでは1です:

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

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

  1. クライアントがTCP接続を開きます
  2. 接続がtcp_keepalive_time数秒間無音の場合は、空のACKパケットを1つ送信します。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キープアライブパケットへの応答および/またはリレーはオプションです

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

..。

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

キープアライブパケットにはデータが含まれておらず、厳密には必要ではなく、使いすぎるとインターウェブのチューブが詰まるリスクがあるためです。

ただし実際には、帯域幅が安くなるにつれて、この懸念は時間の経過とともに減少してきました。したがって、キープアライブパケットは通常ドロップされません。たとえば、Amazon EC2のドキュメントでは、キープアライブを間接的に推奨しているため、AWSでホストしている場合は、キープアライブに頼っても安全ですが、マイレージは異なる場合があります。

TCPタイムアウトの変更

ソケットごと

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

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

Linux

現在構成されているTCPキープアライブ設定は次の場所にあります。

  • /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キープアライブ設定を見つける必要があります。

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

脚注

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

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

3.基本的なGoogle検索から見つけたいくつかの例は、lucwilliams / JavaLinuxNetflonatel / libdontdieです。


とても助かりました、ありがとう!1つの追加:Windowsの場合、KeepAliveTimeの新しい値を有効にするには、再起動が必要です。
geld0r 2016

AIXでは、$ no -a | grep tcp_keepコマンドを使用して現在のTCPキープアライブ設定を照会できます。
JarekPrzygódzki

55

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

JavaのソケットAPIを経由してアプリケーションに「キープアライブ」を公開しsetKeepAlive及びgetKeepAlive方法。

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

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


4
setKeepAlive(true);の場合 間隔はどのくらいですか?...また、Javaはデフォルトの間隔でキープアライブメッセージを送信し続けますか、それともプログラムで送信する必要がありますか?
ケビン・ボイド

3
unixguide.net/network/socketfaq/4.7.shtmlSO_KEEPALIVEの説明があります。それ私が提案したものに対するプロトコルベースのオプションです、OPが望んでいたものでありません...しかし、2時間に1回はアプリケーションにはあまり効果がありません。
Matthew Scharley 2009

4
@MatthewScharley「デフォルトで2時間以上に設定してはいけません」について... 2時間未満が許可されているということですか?
ペースリエ2012

1
@ MatthewScharley- 「その通りですが、それは実装固有です...」。2時間以上のキープアライブ間隔は役に立たないため、実装している人を想像するのは困難です。
スティーブンC

2
@ Daniel-(Javaでの)代替手段は、上記および他の回答で述べたように、手動でキープアライブを実行することです。きれいではありませんが、システムサービスや他のアプリケーションを壊す可能性のあるデフォルトのOS全体の変更よりも良いかもしれません
スティーブンC

34

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

これはTCP仕様によるものです。

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

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


2
アプリケーションに合わせてTCPキープアライブ間隔を変更できます。例:msdn.microsoft.com/en-us/library/dd877220%28VS.85%29.aspx
Dan Berindei 2010年

@ZZCoder「HTTPでは、キープアライブは持続的接続状態を意味します」とはどういう意味ですか?
Pacerier 2012

1
@Pacerier:HTTP/1.0各要求/応答で、サーバーへの再接続が必要でした。以下のためにHTTP/1.1、彼らは導入Keep-Aliveそれは複数のファイルを要求すると「パイプライン」を可能に容易にするための応答を処理して行われた後、接続を殺さないためにサーバーを起動するために使用できるヘッダを、複数のリクエストを送信し、すべてのデータが返されるのを待ちます。
Matthew Scharley 2014年

これは基本的に、多くのHTTPリクエストが同じTCP接続を再利用する/再利用する必要があることを意味します(これらの接続もキープアライブを持っている可能性がありますが、HTTPに従わないため、本質的に異なる概念です)。
イゴールČordaš

24

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

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

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


ああ!ここに良い点を追加します。つまり、NATルーターなどの接続の動作を妨げる可能性のある中間的なことも考慮する必要があります...
Kevin Boyd

4
これは良い点であり、私たちが直接実装していることだけでなく、覚えておくべきことがたくさんあることを思い出させてくれます。また、レミングス!!
Matthew Scharley 2009

p2pファイル共有は両方とも多くのポートをかみ砕き、多くのゾンビ接続を生成するため、NATがアイドル状態の接続をプルーニングする必要がある可能性が高くなることに注意してください。
Artelius 2009

4
必ずしもそうとは限りませんが、TCP接続は、src ip、src port、dest ip、destportの4つの要素で識別されます。したがって、宛先IPが異なる限り、同じ外部(送信元)ポートを再利用できます。
ダンベリンデイ2010年

1
そうそう、その通りです。本当の理由は、メモリの制約とルックアップ時間のために、NATが開いている接続の固定サイズのテーブルを持っていることだと思います。
Artelius 2010年

4

これは、キープアライブに関する補足資料であり、それをより詳細に説明しています。

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

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


1

JAVAソケット– TCP接続はOSレベルで管理され、java.net.Socketは、ソケットごとのレベルでキープアライブパケットのタイムアウトを設定する組み込み関数を提供しません。ただし、Javaソケットのキープアライブオプションを有効にすることはできますが、古いtcp接続の処理には、デフォルトで2時間11分(7200秒)かかります。この原因の接続は、パージする前に非常に長い間利用できます。そこで、ネイティブコード(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の場合、WinsockIOCTLライブラリを使用して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

MicrosoftのドキュメントによるとWindowsの場合

  • 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に固定されており、変更できません。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.