TCP创建连接和关闭连接
来源:互联网 发布:全景展示系统源码 编辑:程序博客网 时间:2024/05/16 13:46
让我们来看看调用connect的背后,TCP做了什么?
创建连接
图示说明:行号用于引用。右箭头( --> )表示一个从TCP A到TCP B的分段。左箭头( <-- )与此相反。省略号(…)表示一个仍然在网络中的Segment
(延迟了)。“XXX”表示一个丢失或被丢弃的segment。圆括号中的是注释。TCP状态表示发送或收到一个segment之后的状态。每一行的中间部分
简略显示了段的内容,包括:系列号,控制标志,ACK域。出于简明考虑,省略了其它部分。
使用捎带数据段做同步是合法合理的(握手阶段捎带数据)。数据会被缓存起来直到连接到达ESTABLISHED状态。
最简单的三次握手如图 1 所示:
TCP A TCP B
1. CLOSED LISTEN
2. SYN-SENT --> <SEQ=100><CTL=SYN> --> SYN-RECEIVED
3. ESTABLISHED <-- <SEQ=300><ACK=101><CTL=SYN,ACK> <-- SYN-RECEIVED
4. ESTABLISHED --> <SEQ=101><ACK=301><CTL=ACK> --> ESTABLISHED
5. ESTABLISHED --> <SEQ=101><ACK=301><CTL=ACK><DATA> --> ESTABLISHED图 1
图1的第2行,TCP A以发送一个SYN段开始,初始系列号是100。在第3行,TCP B发送了一个SYN,并确认它收到了A发送的SYN(ACK=101)。
第4行,TCP A回应一个对TCP B的SYN的确认。第5行,A发送了一些数据。注意,第4行和第5行的段的系列号是相同的,因为ACK不占用系列号空
间。
同时打开(Simultaneous initiation)稍微有点复杂。如图2所示。每一个TCP都要经历从CLOSED 到 SYN-SENT 到 SYN-RECEIVED
到 ESTABLISHED的过程。
PS:同时打开在TCP NAT穿透中用到。
TCP A TCP B1. CLOSED CLOSED2. SYN-SENT --> <SEQ=100><CTL=SYN> ...3. SYN-RECEIVED <-- <SEQ=300><CTL=SYN> <-- SYN-SENT4. ... <SEQ=100><CTL=SYN> --> SYN-RECEIVED5. SYN-RECEIVED --> <SEQ=100><ACK=301><CTL=SYN,ACK> ...6. ESTABLISHED <-- <SEQ=300><ACK=101><CTL=SYN,ACK> <-- SYN-RECEIVED7. ... <SEQ=101><ACK=301><CTL=ACK> --> ESTABLISHEDSimultaneous Connection Synchronization图2
三次握手的合理原则是能够避免旧的连接初始化副本(延迟一段时间后才到达主机,已经失效)引起的曲解。为了处理这种情况,发明了一个专用
的控制消息,reset。处于非同步状态(例如:SYN-SENT, SYN-RECEIVED)的receiving TCP,收到reset后将返回到LISTEN状态。处于同步状
态(ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK, TIME-WAIT)的TCP,收到reset后将终止连接并通知用户。
图3是一个从旧的SYN中恢复的例子。
TCP A TCP B1. CLOSED LISTEN2. SYN-SENT --> <SEQ=100><CTL=SYN> ...3. (duplicate) ... <SEQ=90><CTL=SYN> --> SYN-RECEIVED4. SYN-SENT <-- <SEQ=300><ACK=91><CTL=SYN,ACK> <-- SYN-RECEIVED5. SYN-SENT --> <SEQ=91><CTL=RST> --> LISTEN6. ... <SEQ=100><CTL=SYN> --> SYN-RECEIVED7. SYN-SENT <-- <SEQ=400><ACK=101><CTL=SYN,ACK> <-- SYN-RECEIVED8. ESTABLISHED --> <SEQ=101><ACK=401><CTL=ACK> --> ESTABLISHEDRecovery from Old Duplicate SYN图 3
在第3行,一个旧的SYN到达TCP B,TCP B不知道这是一个旧的SYN(之前没有收到过SYN),因此它把这个SYN看做是一个正常的SYN并响应。
TCP A发现 ACK域是不正确的并返回一个RST,注意SEQ域要设置正确。TCP B收到RST之后,返回到LISTEN状态。
当“正确”的SYN最终到达时(第6行),同步过程按正常情况继续。如果第6行的SYN在RST之前到达,情况就更复杂了,两端都要发送RST
半开连接和其它异常
对于一个已建立的连接,如果其中一端关闭或终止了连接,但另一方还不知道,或者由于Crash导致内存丢失而使两端变得不同步,我们就说该连接
是“half-open”的。试图在这样的连接上发送数据将自动触发reset。然而,半开连接是不正常的,需要合适的恢复过程使其变得正常。
如果连接的A端不存在了,B端的用户试图发送数据,就会导致B收到一个reset控制消息。 这样的消息告诉B有哪里不对劲了,连接应该被终止。
假设两个用户进程A和B正在彼此通信,这时发生了一个crash,导致A的TCP内存丢失。对于这样的情况,一些操作系统会有错误恢复机制。 再次使用
TCP时,A可能重新开始也可能从某个点恢复。即,A可能尝试重新打开连接或者试图通过之前的连接(它相信该连接是打开的)发送数据。对于后一
种情况,将会收到一个来自本地TCP的错误消息“连接未打开”。 尝试创建连接时,A的TCP将发送一个SYN段。这种情况如图4所示。TCP A奔溃后,
用户尝试重新连接。而TCP B,认为连接已经是打开的。
TCP A TCP B1. (CRASH) (send 300,receive 100)2. CLOSED ESTABLISHED3. SYN-SENT --> <SEQ=400><CTL=SYN> --> (??)4. (!!) <-- <SEQ=300><ACK=100><CTL=ACK> <-- ESTABLISHED5. SYN-SENT --> <SEQ=100><CTL=RST> --> (Abort!!)6. SYN-SENT CLOSED7. SYN-SENT --> <SEQ=400><CTL=SYN> -->Half-Open Connection Discovery图 4
第3行,当SYN到来时,TCP B,正处于同步状态,而且收到的段不在接收窗口内,随即响应一个ACK指明它期望的下一个字节(ACK 100)。TCP A看
到,这个段没有确认任何它发送的东西,就知道处于不同步状态了,也就是发现了一个“半开”连接,A就会发送一个RST。第5行,TCP B终止了连
接。TCP A将继续尝试建立连接。接下来问题简化为如图 1所示的简单的三次握手。
另一个有趣的例子是,TCP A 奔溃了,而TCP B尝试在它认为是同步的连接上发送数据。如图 5所示。在这种情况下,从 TCP B到达TCP A的数据,是
不能被接受的,因为连接不存在(没有进程在相应端口监听数据),所以TCP A会发送一个RST。TCP B收到RST(该RST要是合适的)之后就会终止连
接。
TCP A TCP B1. (CRASH) (send 300,receive 100)2. (??) <-- <SEQ=300><ACK=100><DATA=10><CTL=ACK> <-- ESTABLISHED3. --> <SEQ=100><CTL=RST> --> (ABORT!!)Active Side Causes Half-Open Connection Discovery图 5
在图 6中,两个TCPs A和B处于被动连接状态,都在等待着SYN。一个旧的SYN副本(An old duplicate)到达TCP B(第2行)。TCP返回一个
SYN-ACK(第3行),这导致TCP A产生一个RST(第3行的ACK是不被接受的,因为在A看来,它没有发送过SYN)。TCP B接受reset并返回到被动接
收状态。
TCP A TCP B1. LISTEN LISTEN2. ... <SEQ=Z><CTL=SYN> --> SYN-RECEIVED3. (??) <-- <SEQ=X><ACK=Z+1><CTL=SYN,ACK> <-- SYN-RECEIVED4. --> <SEQ=Z+1><CTL=RST> --> (return to LISTEN!)5. LISTEN LISTENOld Duplicate SYN Initiates a Reset on two Passive Sockets图 6
还有很多其它的可能情况,它们都遵从如下规则来产生和处理RST。
RST的产生
一个通用的规则是,只要收到一个显然不属于当前连接的段就发送一个RST。否则就不要发送。
比如,没有发送SYN,但是收到了SYN-ACK
可以分为如下三类:
- 如果连接不存在(CLOSED),收到任何非RST段都会回应一个RST。典型的,任何发送到不存在连接的SYNs都以这种方式来处理。比如:向某
个主机上没有进程监听的端口发起连接,connect返回ECONNREFUSED。 - 如果连接处于任何非同步状态(LISTEN, SYS-SENT, SYN-RECEIVED),并且收到的段的确认在窗口外,或者安全层不匹配,就会发
送一个RST. - 如果连接处于同步状态(ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK, TIME-WAIT),收到任何
不可接受的段(SEQ在窗口外,或者ACK是是无效的),都要回应一个ACK段,其中包含当前的SEQ和一个指明下一个期望接收字节的
ACK,连接状态保持不变。
RST的处理
在所有非SYN-SENT状态下,TCP首先通过检查SEQ域来验证所有的RST段的合法性。如果它的SEQ在窗口内,就是合法的。在SYN-SENT状
态下,如果ACK域确认了SYN,那么这个RST就是合法的。RST的接收者首先验证它(非法的RST都会忽略掉),然后再决定要不要改变状
态。如果接收者正处于LISTEN状态,就忽略RST。如果接收者处于SYN-RECEIVED状态,并且之前处于LISTEN状态,就返回到LISTEN状
态,否则接收者终止连接并转换到CLOSED状态。如果接收者处于其它状态,收到RST后,就终止连接并建议用户转换到CLOSED状态。
关闭连接
基本上有3种情况导致连接关闭:
- 本地用户告诉TCP关闭连接
- 远程TCP通过发送FIN控制信号关闭
- 两端用户同时CLOSE
Case 1:本地用户主动关闭
在这种情况下,会构造一个FIN段并放到发送队列中。TCP不在接收任何SENDs,并且进入FIN-WAIT-1状态。这一状态允许RECEIVEs。之前发送的数
据段和FIN段都会被重传直到收到确认。当另一端的TCP已经确认了FIN并且发送了它自己的FIN,第一个TCP可以确认这个FIN。注意一个收到FIN的
TCP将会发送相应的ACK,但是不会发送它自己的FIN,除非用户也关闭了该连接。
Case 2:TCP从网络上接收到一个FIN
从网络上接收到FIN的TCP能够ACK它,并且告诉用户连接正在关闭。用户对此的反应是,调用close,于是TCP在发送完所有待发送的数据之后发送一
个FIN到连接的另一端。TCP一直等到它发送的FIN被确认,然后删除该连接。如果一直没有收到ACK,超时之后连接就会被终止并通知用户。
Case 3: 两边的用户同时关闭
同时关闭的情况下,连接双方交换FIN,并进行确认,当两边都收到ACK后,连接就被删除。
TCP A TCP B1. ESTABLISHED ESTABLISHED2. (Close)FIN-WAIT-1 --> <SEQ=100><ACK=300><CTL=FIN,ACK> --> CLOSE-WAIT3. FIN-WAIT-2 <-- <SEQ=300><ACK=101><CTL=ACK> <-- CLOSE-WAIT4. (Close)TIME-WAIT <-- <SEQ=300><ACK=101><CTL=FIN,ACK> <-- LAST-ACK5. TIME-WAIT --> <SEQ=101><ACK=301><CTL=ACK> --> CLOSED6. (2 MSL)CLOSED正常关闭系列图图 5
TCP A TCP B1. ESTABLISHED ESTABLISHED2. (Close) (Close)FIN-WAIT-1 --> <SEQ=100><ACK=300><CTL=FIN,ACK> ... FIN-WAIT-1<-- <SEQ=300><ACK=100><CTL=FIN,ACK> <--... <SEQ=100><ACK=300><CTL=FIN,ACK> -->3. CLOSING --> <SEQ=101><ACK=301><CTL=ACK> ... CLOSING<-- <SEQ=301><ACK=101><CTL=ACK> <--... <SEQ=101><ACK=301><CTL=ACK> -->4. TIME-WAIT TIME-WAIT(2 MSL) (2 MSL)CLOSED CLOSED同时打开系列图
- TCP创建连接和关闭连接
- TCP的连接和关闭
- TCP建立和关闭连接
- TCP的连接和关闭
- TCP的连接和关闭
- TCP的建立连接和关闭连接
- webSocket.java创建连接和关闭连接
- TCP连接的建立和关闭
- TCP连接建立和关闭流程
- tcp连接关闭详解和注意事项
- TCP连接关闭—close和shutdown
- TCP连接的建立和关闭详解
- TCP连接关闭—close和shutdown
- TCP协议连接和关闭详解
- tcp连接关闭详解和注意事项
- TCP连接和关闭的过程
- TCP连接关闭总结
- 关闭tcp连接
- oracle字符集(二)
- HDU--杭电--2066--一个人的旅行--最短路
- 庞果网在线编程子序列的个数问题ruby解答
- HashMap与HashTable区别
- [Ajax]ajax入门
- TCP创建连接和关闭连接
- Dos命令总结
- 结构体操作
- 学习PLS_INTEGER,BINARY_INTEGER,INTEGER,NUMBER的概念及区别以及在性能方面的差异
- 【Unity Shaders】Diffuse Shading——创建一个基本的Surface Shader
- android SQliteDatabase 数据的更新问题
- C++语言中的细节_1
- 一个概率算法问题
- linux实现简单 PPPOE服务器