TCP异常终止
TCP異常終止 Reset報文
TCP 的異常終止是相對于正常釋放 TCP 連接的過程而言的,我們都知道,TCP 連接的建立是通過三次握手完成的,而 TCP 正常釋放連接是通過四次揮手來完成,但是有些情況下,TCP 在交互過程中會出現(xiàn)一些意想不到的情況,導(dǎo)致 TCP 無法按照正常的四次揮手來釋放連接,如果此時不通過其他的方式來釋放 TCP 連接的話,這個 TCP 連接將會一直存在,占用系統(tǒng)的部分資源。在這種情況下,我們就需要有一種能夠釋放 TCP 連接的機制,這種機制就是 TCP 的 Reset 報文。Reset 報文是指 TCP 報頭的標志字段中的 Reset 位設(shè)置為一的報文,如下圖所示:
我們在實際的工作環(huán)境中,導(dǎo)致某一方發(fā)送 Reset 報文的情形有多種。
服務(wù)器端口未對外提供服務(wù)
客戶端嘗試與服務(wù)器未對外提供服務(wù)的端口建立 TCP 連接,服務(wù)器將會直接向客戶端發(fā)送 Reset 報文。
通過共享 WiFi 熱點的方式,用 Wireshark 抓包來看這個過程中網(wǎng)絡(luò)包的交互,在 Android 客戶端 Java 代碼中訪問服務(wù)器一個不提供服務(wù)的端口 442:
如上圖,第 1 號和 2 號包,是客戶端發(fā)向服務(wù)器,用于建立 TCP 連接的 SYN 包,隨后立即就收到了服務(wù)器返回的 [RST,ACK] 包。
以 OkHttp 做為客戶端 Java HttpStack 庫,這種情況下將拋出如下異常:
java.net.ConnectException: Failed to connect to www.wolfcstech.com/139.196.224.72:442at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:222)at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:146)at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:186)at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:121)at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:100)at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at com.netease.netlib.OkHttp3Utils$MyInterceptor.intercept(OkHttp3Utils.java:29)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:179)at okhttp3.RealCall$AsyncCall.execute(RealCall.java:129)at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)at java.lang.Thread.run(Thread.java:841) Caused by: java.net.ConnectException: failed to connect to www.wolfcstech.com/139.196.224.72 (port 442) after 10000ms: isConnected failed: ECONNREFUSED (Connection refused)at libcore.io.IoBridge.isConnected(IoBridge.java:223)at libcore.io.IoBridge.connectErrno(IoBridge.java:161)at libcore.io.IoBridge.connect(IoBridge.java:112)at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:192)at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:460)at java.net.Socket.connect(Socket.java:833)at okhttp3.internal.platform.AndroidPlatform.connectSocket(AndroidPlatform.java:63)at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:220)... 24 more Caused by: libcore.io.ErrnoException: isConnected failed: ECONNREFUSED (Connection refused)at libcore.io.IoBridge.isConnected(IoBridge.java:208)OkHttp 拋出了 Java 異常 java.net.ConnectException,然而 libcore 層的異常顯示,連接被拒絕:
libcore.io.ErrnoException: isConnected failed: ECONNREFUSED (Connection refused)通信某一方異常崩潰
客戶端和服務(wù)器的某一方在交互的過程中發(fā)生異常(如程序崩潰等),該方系統(tǒng)將向?qū)Χ税l(fā)送 TCP Reset 報文,告之對方釋放相關(guān)的 TCP 連接,如下圖所示:
異常終止的一方,在進程退出時,釋放占用的資源,包括 socket,TCP、UDP 端口等。站在異常退出的這一方的角度來看,對端是在訪問一個沒有打開的 socket。
通過如下方式模擬數(shù)據(jù)發(fā)送時,服務(wù)器端異常退出的情況:
HTTPS 請求-發(fā)送數(shù)據(jù)
前面的操作過程中,執(zhí)行 HTTPS 請求,通過 Wireshark 抓包,得到如下結(jié)果:
第 116 號包,Android 手機發(fā)送 TCP SYN 包,與代理服務(wù)器建立 TCP 連接。到第 118 號包,完成 TCP 三次握手,連接建立完成。
第119 號包到第121 號包,Android 應(yīng)用請求代理服務(wù)器建立隧道連接,隧道連接建立完成。
第 123 號包是代理服務(wù)器進程在退出時,發(fā)送了 [FIN ACK] 結(jié)束 TCP 連接。
第 130 號包是在代理服務(wù)器關(guān)閉之后,Android 應(yīng)用發(fā)送的數(shù)據(jù),TLS 握手的 Client Hello 。隨后代理服務(wù)器主機立即響應(yīng)了 RST 包給 Android 應(yīng)用。
經(jīng)過上面的操作,OkHttp 的執(zhí)行將報錯退出,報出的異常如下:
javax.net.ssl.SSLException: Connection closed by peerat com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:405)at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:267)at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:237)at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:148)at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:186)at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:121)at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:100)at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at com.netease.netlib.OkHttp3Utils$MyInterceptor.intercept(OkHttp3Utils.java:29)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:179)at okhttp3.RealCall$AsyncCall.execute(RealCall.java:129)at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)at java.lang.Thread.run(Thread.java:841)報出了 javax.net.ssl.SSLException: Connection closed by peer。
修改前面的操作,讓 Android 客戶端直接與遠程 HTTP 服務(wù)器連接,在連接建立完成的時候,殺掉 HTTP 服務(wù)進程,其它保持完全不變,則無論是抓到的包,還是 OkHttp 報出的異常,基本都沒有改變。抓到的包如下:
OkHttp 拋出的異常如下:
javax.net.ssl.SSLException: Connection closed by peerat com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:405)at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:267)at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:237)at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:148)at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:186)at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:121)at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:100)at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at com.netease.netlib.OkHttp3Utils$MyInterceptor.intercept(OkHttp3Utils.java:29)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:179)at okhttp3.RealCall$AsyncCall.execute(RealCall.java:129)at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)可見,執(zhí)行 HTTPS 請求,在發(fā)送數(shù)據(jù)時,代理服務(wù)器或遠程 HTTP 服務(wù)器被殺掉的話,它們都會執(zhí)行正常結(jié)束 TCP 連接的操作。而在 Android 端,OkHttp 將報出異常 javax.net.ssl.SSLException: Connection closed by peer。
HTTP 請求-發(fā)送數(shù)據(jù)
前面的操作過程中,使用代理時,執(zhí)行 HTTP 請求,通過 Wireshark 抓包,得到如下結(jié)果:
2017-06-07 15-22-53屏幕截圖.png
Android 客戶端與代理服務(wù)器的連接建立完成之后,立即殺掉代理服務(wù)器進程,代理服務(wù)器向 Android 客戶端發(fā)送了 [FIN, ACK] 以結(jié)束 TCP 連接。隨后 Android 客戶端發(fā)出 HTTP 請求,將立即收到代理服務(wù)器進程發(fā)回的 RST 包。
OkHttp 將報出如下的異常:
java.io.IOException: unexpected end of stream on Connection{www.wolfcstech.com:80, proxy=HTTP@10.240.252.17:8888 hostAddress=/10.240.252.17:8888 cipherSuite=none protocol=http/1.1}at okhttp3.internal.http1.Http1Codec.readResponseHeaders(Http1Codec.java:205)at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:67)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at com.netease.netlib.OkHttp3Utils$MyInterceptor.intercept(OkHttp3Utils.java:29)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:179)at okhttp3.RealCall$AsyncCall.execute(RealCall.java:129)at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)at java.lang.Thread.run(Thread.java:841) Caused by: java.io.EOFException: \n not found: size=0 content=…at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:215)at okhttp3.internal.http1.Http1Codec.readResponseHeaders(Http1Codec.java:189)... 22 more讓 Android 客戶端直接與遠端 HTTP 服務(wù)器相連,則抓到的包如下:
在服務(wù)器進程被殺掉的時候,同樣發(fā)出了 [FIN ACK] 來結(jié)束 TCP 連接。此時 OkHttp 報出的異常將像下面這樣:
java.io.IOException: unexpected end of stream on Connection{www.wolfcstech.com:80, proxy=DIRECT@ hostAddress=www.wolfcstech.com/139.196.224.72:80 cipherSuite=none protocol=http/1.1}at okhttp3.internal.http1.Http1Codec.readResponseHeaders(Http1Codec.java:205)at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:67)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at com.netease.netlib.OkHttp3Utils$MyInterceptor.intercept(OkHttp3Utils.java:29)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:179)at okhttp3.RealCall$AsyncCall.execute(RealCall.java:129)at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)at java.lang.Thread.run(Thread.java:841)Caused by: java.io.EOFException: \n not found: size=0 content=…at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:215)at okhttp3.internal.http1.Http1Codec.readResponseHeaders(Http1Codec.java:189)... 22 more可見,執(zhí)行 HTTP 請求,在發(fā)送數(shù)據(jù)時,代理服務(wù)器或遠程 HTTP 服務(wù)器被殺掉的話,它們都會執(zhí)行正常結(jié)束 TCP 連接的操作。而在 Android 端,OkHttp 將報出異常 java.io.IOException: unexpected end of stream on Connection{www.wolfcstech.com:80, proxy=DIRECT@ hostAddress=www.wolfcstech.com/139.196.224.72:80 cipherSuite=none protocol=http/1.1}。
通過如下方式模擬數(shù)據(jù)接收時,服務(wù)器端異常退出的情況:
HTTPS 請求 - 接收響應(yīng)
按上面的操作,在接收響應(yīng)的過程中,突然殺掉服務(wù)器進程,抓到的包如下:
在這種情況下,服務(wù)器沒有來得及給客戶端發(fā)送 [FIN, ACK] 包結(jié)束 TCP 連接,而是客戶端首先發(fā)出了 [FIN, ACK] 包 。
此時 OkHttp 報出了如下的異常:
java.net.ProtocolException: unexpected end of streamat okhttp3.internal.http1.Http1Codec$FixedLengthSource.read(Http1Codec.java:387)at okio.Buffer.writeAll(Buffer.java:996)at okio.RealBufferedSource.readString(RealBufferedSource.java:189)at okhttp3.ResponseBody.string(ResponseBody.java:174)at com.netease.volleydemo.MainActivity$2$1.onResponse(MainActivity.java:207)at okhttp3.RealCall$AsyncCall.execute(RealCall.java:135)at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)at java.lang.Thread.run(Thread.java:841)HTTP/2 請求 - 接收響應(yīng)
如果前面的請求是 HTTP/2 請求,在接收響應(yīng)的過程中,突然殺掉服務(wù)器進程,抓到的包則如下:
服務(wù)器來不及結(jié)束 TCP 連接??蛻舳讼蚍?wù)器發(fā)送數(shù)據(jù)時,收到了服務(wù)器響應(yīng)的 RST。OkHttp 拋出如下錯誤:
okhttp3.internal.http2.StreamResetException: stream was reset: CANCELat okhttp3.internal.http2.Http2Stream$FramingSource.checkNotClosed(Http2Stream.java:436)at okhttp3.internal.http2.Http2Stream$FramingSource.read(Http2Stream.java:338)at okio.ForwardingSource.read(ForwardingSource.java:35)at okio.Buffer.writeAll(Buffer.java:996)at okio.RealBufferedSource.readString(RealBufferedSource.java:189)at okhttp3.ResponseBody.string(ResponseBody.java:174)at com.netease.volleydemo.MainActivity$2$1.onResponse(MainActivity.java:207)at okhttp3.RealCall$AsyncCall.execute(RealCall.java:135)at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)HTTP 請求 - 接收響應(yīng)
在接收響應(yīng)的過程中,突然殺掉服務(wù)器進程,抓到的包如下:
服務(wù)器正常結(jié)束掉了 TCP 連接。OkHttp 拋出如下錯誤:
java.net.ProtocolException: unexpected end of streamat okhttp3.internal.http1.Http1Codec$FixedLengthSource.read(Http1Codec.java:387)at okio.Buffer.writeAll(Buffer.java:996)at okio.RealBufferedSource.readString(RealBufferedSource.java:189)at okhttp3.ResponseBody.string(ResponseBody.java:174)at com.netease.volleydemo.MainActivity$2$1.onResponse(MainActivity.java:207)at okhttp3.RealCall$AsyncCall.execute(RealCall.java:135)at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)在 Android 客戶端從 HTTP 接收數(shù)據(jù)時, HTTP 服務(wù)器意外掛掉,HTTPS 和 HTTP 請求,拋出了異常 java.net.ProtocolException: unexpected end of stream ,而 HTTP/2 請求,則拋出了異常 okhttp3.internal.http2.StreamResetException: stream was reset: CANCEL。對于這三種請求,在 HTTP 服務(wù)器結(jié)束退出時,都沒有來得及發(fā)送 [FIN, ACK] 結(jié)束 TCP 連接,[FIN, ACK] 均是首先由 Android 客戶端發(fā)出。
這分為兩種情況,一是發(fā)送數(shù)據(jù)的一方意外崩潰,接收數(shù)據(jù)的一方看到了什么?二是接收數(shù)據(jù)的一方意外崩潰,發(fā)送數(shù)據(jù)的一方又看到了什么?
讀寫的角度,站在 Android 客戶端的角度來看,如果是接收數(shù)據(jù)的時候,對端意外退出,它將會發(fā)生什么?二是在寫數(shù)據(jù)的時候,對端意外退出,它又將看到什么?
數(shù)據(jù)接收的一方終止連接的話,數(shù)據(jù)發(fā)送的一方將看到如下的景象:
image_20170527160621.png
從抓到的包來看,HTTP 請求結(jié)束之前,客戶端把連接關(guān)閉的話,TCP正常結(jié)束的揮手流程會走,FIN 會發(fā)給服務(wù)器。不過后續(xù)在服務(wù)器收到 FIN 之前發(fā)的數(shù)據(jù)還會繼續(xù)到達,客戶端收到這些包的時候會發(fā)送 RST
3, 接收端收到 TCP 報文,但是發(fā)現(xiàn)該 TCP 的報文,并不在其已建立的 TCP 連接列表內(nèi),則其直接向?qū)Χ税l(fā)送reset報文,如下圖所示:
為什么會出現(xiàn)這種情況?TCP 報文,具體指那種類型的報文,SYN 還是 DATA?是 TCP 報文路由出錯了,被發(fā)送給了錯誤的主機了么?還是 TCP 連接已經(jīng)被接收數(shù)據(jù)的一方關(guān)掉了?
一種典型的場景是,某個內(nèi)網(wǎng)中的一臺主機,以公網(wǎng) IP 訪問位于相同內(nèi)網(wǎng)的 Web 服務(wù)器。NAT 本身就分支持 hairpin 和 不支持 hairpin 之分,也就是是否支持回傳。內(nèi)網(wǎng)中的一臺主機,通過相同內(nèi)網(wǎng)中一臺 Web 服務(wù)器的公網(wǎng)地址訪問該 Web 服務(wù)器的時候,連接建立的 SYN 包發(fā)到 NAT 處,NAT 發(fā)現(xiàn)目標主機就在內(nèi)網(wǎng)中,于是它沒有為發(fā)起連接的主機做 NAT 映射,直接將包轉(zhuǎn)給了目的 Web 服務(wù)器主機,此時這個包的源 IP 與目的 IP 將都是內(nèi)網(wǎng)的私有 IP 地址。后面 Web 服務(wù)器收到 SYN 包,回一個 SYN ACK 包,由于源主機沒有做 NAT 映射,此時這個 SYN ACK 包在發(fā)給連接發(fā)起的源主機時,它的目的 IP 和 源 IP 也將都是內(nèi)網(wǎng)私有 IP。這與源主機的期待不同,它本來期待回的 SYN ACK 包的源 IP 是一個公網(wǎng) IP的。
4, 在交互的雙方中的某一方長期未收到來自對方的確認報文,則其在超出一定的重傳次數(shù)或時間后,會主動向?qū)Χ税l(fā)送reset報文釋放該TCP連接,如下圖所示:
5, 有些應(yīng)用開發(fā)者在設(shè)計應(yīng)用系統(tǒng)時,會利用reset報文快速釋放已經(jīng)完成數(shù)據(jù)交互的TCP連接,以提高業(yè)務(wù)交互的效率,如下圖所示:
參考文檔
-
TCP異常終止(reset報文)
-
Caddy tls configuration
總結(jié)
- 上一篇: WiFi 热点共享设置
- 下一篇: BufferQueue 和 grallo