せっかちな人向け:
setsockopt()
、ioctl()
などを使用して、Linuxの単一接続の_/proc/sys/net/ipv4/tcp_retries2
_の値を変更する方法、またはそれは可能ですか?
長い説明:
長いポーリングHTTPリクエストを使用するアプリケーションを開発しています。サーバー側では、クライアントが接続を閉じたときにそれを知る必要があります。精度は重要ではありませんが、15分にはなり得ません。 1分近ければ問題ありません。
概念に慣れていない人のために、長いポーリングHTTPリクエストは次のように機能します。
私のアプリケーションでは、サーバーは時々「ハートビート」をクライアントに送信します(デフォルトでは30秒)。ハートビートは、応答チャンクとして送信される単なる改行文字です。これは、接続が失われたことを通知できるように、回線をビジーに保つことを目的としています。
クライアントが正しくシャットダウンしても問題はありません。しかし、強制的にシャットダウンした場合(たとえば、クライアントマシンの電源が切れた場合)、TCPリセットは送信されません。この場合、サーバーはクライアントが送信しないハートビートを送信しますACK:この後、サーバーはあきらめてアプリケーション層(HTTPサーバー)に障害を報告してから約15分間パケットを再送信し続けます。
_/proc/sys/net/ipv4/
_の次のファイルに書き込むことで、再送信時間を制御できます。
_tcp_retries1 - INTEGER
This value influences the time, after which TCP decides, that
something is wrong due to unacknowledged RTO retransmissions,
and reports this suspicion to the network layer.
See tcp_retries2 for more details.
RFC 1122 recommends at least 3 retransmissions, which is the
default.
tcp_retries2 - INTEGER
This value influences the timeout of an alive TCP connection,
when RTO retransmissions remain unacknowledged.
Given a value of N, a hypothetical TCP connection following
exponential backoff with an initial RTO of TCP_RTO_MIN would
retransmit N times before killing the connection at the (N+1)th RTO.
The default value of 15 yields a hypothetical timeout of 924.6
seconds and is a lower bound for the effective timeout.
TCP will effectively time out at the first RTO which exceeds the
hypothetical timeout.
RFC 1122 recommends at least 100 seconds for the timeout,
which corresponds to a value of at least 8.
_
_tcp_retries2
_のデフォルト値は確かに8であり、15分(900秒)の再送信の私の経験は、上記で引用したカーネルのドキュメントに沿っています。
たとえば、_tcp_retries2
_の値を5に変更すると、接続はより速く切断されます。しかし、このように設定すると、システム内のすべての接続に影響するため、この1つの長いポーリング接続のみに設定したいのです。
RFC 1122からの引用:
_4.2.3.5 TCP Connection Failures
Excessive retransmission of the same segment by TCP
indicates some failure of the remote Host or the Internet
path. This failure may be of short or long duration. The
following procedure MUST be used to handle excessive
retransmissions of data segments [IP:11]:
(a) There are two thresholds R1 and R2 measuring the amount
of retransmission that has occurred for the same
segment. R1 and R2 might be measured in time units or
as a count of retransmissions.
(b) When the number of transmissions of the same segment
reaches or exceeds threshold R1, pass negative advice
(see Section 3.3.1.4) to the IP layer, to trigger
dead-gateway diagnosis.
(c) When the number of transmissions of the same segment
reaches a threshold R2 greater than R1, close the
connection.
(d) An application MUST be able to set the value for R2 for
a particular connection. For example, an interactive
application might set R2 to "infinity," giving the user
control over when to disconnect.
(e) TCP SHOULD inform the application of the delivery
problem (unless such information has been disabled by
the application; see Section 4.2.4.1), when R1 is
reached and before R2. This will allow a remote login
(User Telnet) application program to inform the user,
for example.
_
Linuxの_tcp_retries1
_と_tcp_retries2
_はRFCの_R1
_と_R2
_に対応しているように思えます。 RFCは、(項目d)で、準拠する実装では_R2
_の値の設定を許可する必要があることを明確に述べていますが、setsockopt()
、ioctl()
を使用してそれを行う方法は見つかりませんでしたまたはそのような。
別のオプションは、_R1
_を超えたときに通知を受け取ることです(項目e)。これは_R2
_の設定ほど良くありませんが、_R1
_はすぐに(数秒で)ヒットし、_R1
_の値は接続ごとに設定できないと思います。少なくともRFCはそれを必要としません。
これはカーネル2.6.37で追加されたようです。 Commit diff カーネルGitからの抜粋 change log 以下からの抜粋;
コミットdca43c75e7e545694a9dd6288553f55c53e2a3a3著者:Jerry Chu日付:Fri Aug 27 19:13:28 2010 +0000
tcp: Add TCP_USER_TIMEOUT socket option. This patch provides a "user timeout" support as described in RFC793. The socket option is also needed for the the local half of RFC5482 "TCP User Timeout Option". TCP_USER_TIMEOUT is a TCP level socket option that takes an unsigned int, when > 0, to specify the maximum amount of time in ms that transmitted data may remain unacknowledged before TCP will forcefully close the corresponding connection and return ETIMEDOUT to the application. If 0 is given, TCP will continue to use the system default. Increasing the user timeouts allows a TCP connection to survive extended periods without end-to-end connectivity. Decreasing the user timeouts allows applications to "fail fast" if so desired. Otherwise it may take upto 20 minutes with the current system defaults in a normal WAN environment. The socket option can be made during any state of a TCP connection, but is only effective during the synchronized states of a connection (ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, or LAST-ACK). Moreover, when used with the TCP keepalive (SO_KEEPALIVE) option, TCP_USER_TIMEOUT will overtake keepalive to determine when to close a connection due to keepalive failure. The option does not change in anyway when TCP retransmits a packet, nor when a keepalive probe will be sent. This option, like many others, will be inherited by an acceptor from its listener. Signed-off-by: H.K. Jerry Chu <[email protected]> Signed-off-by: David S. Miller <[email protected]>
Kimvais で説明されている_TCP_USER_TIMEOUT
_ソケットオプションが利用可能な場合は、それを使用することをお勧めします。そのソケットオプションが存在しない古いカーネルでは、SIOCOUTQ
ioctl()
を繰り返し呼び出して、ソケット送信キューのサイズを決定できます-送信キューがタイムアウトしても減少しない場合これは、ACKが受信されていないことを示し、ソケットを閉じることができます。
少し考えて(そしてグーグルで)、あなたは変更できないという結論に達しましたtcp_retries1
およびtcp_retries2
何らかのパッチをカーネルに適用しない限り、単一ソケットの値。それはあなたにとって実現可能ですか?
それ以外の場合は、TCP_KEEPALIVE
ソケットオプションは、接続がまだアクティブかどうかを確認することを目的としています(これはまさにあなたが達成しようとしていることなので、理にかなっています)。デフォルトでは約2時間後に切断されるため、デフォルトのパラメーターを少し調整する必要があることに注意してください!!!
これは私の理解のためです。 tcp_retries2は、接続を削除する前にシステムによって許可される再送信の数です。したがって、送信されたデータが未確認のままになる最大時間を指定するTCP_USER_TIMEOUTを使用してtcp_retries2のデフォルト値を変更する場合は、 TCP_USER_TIMEOUTが正しいですか?
その場合、conctionはより長い時間待機し、データパケットを再送信しません。何かが間違っている場合は、私を修正してください。