HTTPキープアライブについて聞いたことがありますが、今のところ、リモートサーバーとのソケット接続を開きたいと思います。
これで、このソケット接続は永久に開いたままになりますか、それともHTTPキープアライブと同様にそれに関連付けられたタイムアウト制限がありますか?
8 に答える
TCPソケット接続には「存続」がありますか?
簡単な答えは「はい」です。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秒
プロセスは次のように機能します。
- クライアントがTCP接続を開きます
- 接続が数秒間無音の場合は、
tcp_keepalive_time
空のACK
パケットを1つ送信します。1 ACK
サーバーは独自 の対応するもので応答しましたか?- いいえ
- 数秒待って
tcp_keepalive_intvl
から、別のACK
ACK
送信されたプローブの数がに等しくなるまで繰り返しtcp_keepalive_probes
ます。- この時点で応答がない場合は、を送信し
RST
て接続を終了します。
- 数秒待って
- はい:手順2に戻ります
- いいえ
このプロセスはほとんどのオペレーティングシステムでデフォルトで有効になっているため、もう一方の端が2時間11分(7200秒+ 75 * 9秒)応答しなくなると、デッドTCP接続は定期的にプルーニングされます。
ガッチャ
2時間のデフォルト
デフォルトでは、接続が2時間アイドル状態になるまでプロセスが開始されないため、古いTCP接続は、プルーニングされる前に非常に長い時間残る可能性があります。これは、データベース接続などの高価な接続にとって特に有害です。
キープアライブはオプションです
RFC 1122 4.2.3.6によると、TCPキープアライブパケットへの応答および/またはリレーはオプションです。
実装者は、TCP実装に「キープアライブ」を含めることができますが、この方法は広く受け入れられていません。キープアライブが含まれている場合、アプリケーションはTCP接続ごとにキープアライブをオンまたはオフにできる必要があり、デフォルトでオフになっている必要があります。
..。
データを含まないACKセグメントは、TCPによって確実に送信されないことを覚えておくことが非常に重要です。
キープアライブパケットにはデータが含まれておらず、厳密には必要ではなく、使いすぎるとインターウェブのチューブが詰まるリスクがあるという理由があります。
ただし、実際には、帯域幅が安くなるにつれて、この懸念は時間の経過とともに減少してきました。したがって、キープアライブパケットは通常ドロップされません。たとえば、 Amazon EC2のドキュメントでは、Keep-Aliveを間接的に推奨しているため、AWSでホスティングしている場合は、Keep-Aliveに頼っても安全ですが、マイレージは異なる場合があります。
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は、秒を使用するLinuxとは対照的に、ミリ秒単位で定義keepidle
します。keepintvl
再起動後もこれらの設定を保持するプロパティを設定でき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/JavaLinuxNetとflonatel/libdontdieです。
TCPソケットは、閉じられるまで開いたままになります。
とはいえ、実際にデータを送信せずに接続の切断(ルーターの停止などの切断など)を実際に送信せずに検出することは非常に難しいため、ほとんどのアプリケーションは、確認のために、ある種のピンポン反応を頻繁に実行します。接続はまだ実際に生きています。
SO_KEEPALIVEソケットオプションを探しています。
Java Socket APIは、メソッドsetKeepAlive
とメソッドを介してアプリケーションに「キープアライブ」を公開しgetKeepAlive
ます。
編集:SO_KEEPALIVEは、「実際の」データを送信せずにOSネットワークプロトコルスタックに実装されます。キープアライブ間隔はオペレーティングシステムに依存し、カーネルパラメータを介して調整できる場合があります。
データが送信されないため、SO_KEEPALIVEはネットワーク接続の有効性のみをテストでき、ソケットが接続されているサービスの有効性はテストできません。後者をテストするには、サーバーにメッセージを送信して応答を取得することを含む何かを実装する必要があります。
TCPキープアライブとHTTPキープアライブは非常に異なる概念です。TCPでは、キープアライブは、古い接続を検出するために送信される管理パケットです。HTTPでは、キープアライブは持続的接続状態を意味します。
これはTCP仕様によるものです。
キープアライブパケットは、ある間隔内に接続に対してデータまたは確認応答パケットが受信されなかった場合にのみ送信する必要があります。この間隔は構成可能である必要があり、デフォルトで2時間以上である必要があります。
ご覧のとおり、ほとんどのアプリケーションでは、デフォルトのTCPキープアライブ間隔が長すぎます。アプリケーションプロトコルにキープアライブを追加する必要がある場合があります。
マスカレードNATの背後にいる場合(最近のほとんどのホームユーザーがそうであるように)、外部ポートのプールは限られており、これらはTCP接続間で共有する必要があります。したがって、マスカレードNATは、特定の期間データが送信されなかった場合に接続が終了したと見なす傾向があります。
これと他のそのような問題(2つのエンドポイントの間のどこか)は、合理的なアイドル期間の後にデータを送信しようとすると、接続が「機能」しなくなることを意味する可能性があります。ただし、データを送信しようとするまで、これを発見できない場合があります。
キープアライブを使用すると、接続が回線のどこかで中断される可能性が低くなり、接続の切断をより早く見つけることができます。
キープアライブに関する補足資料がいくつかあります。これは、キープアライブをより詳細に説明しています。
http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO
Javaでは実際のキープアライブ時間を制御できないため、Linuxカーネル(またはprocベースのOS)を使用している場合は、例を使用してキープアライブ時間を変更できます。
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 struct(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リフレクションを使用して取得します。
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に固定されており、変更できません。