`

TCP-TCP连接3/4次握手

 
阅读更多
TCP建立连接
在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接:
(1) 第一次握手:建立连接时,客户端A发送SYN包(SYN=j)到服务器B,并进入SYN_SEND状态,等待服务器B确认。
(2) 第二次握手:服务器B收到SYN包,必须确认客户A的SYN(ACK=j+1),同时自己也发送一个SYN包(SYN=k),即SYN+ACK包,此时服务器B进入SYN_RECV状态。
(3) 第三次握手:客户端A收到服务器B的SYN+ACK包,向服务器B发送确认包ACK(ACK=k+1),此包发送完毕,客户端A和服务器B进入ESTABLISHED状态,完成三次握手。
完成三次握手,客户端与服务器开始传送数据。
如图1所示:

                               图1 TCP三次握手建立连接

TCP关闭连接
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭,采用四次挥手关闭连接。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
(1)客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送(报文段4)。
(2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号。
(3)服务器B关闭与客户端A的连接,发送一个FIN给客户端A(报文段6)。
(4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)。
如图2所示:


                               图2  TCP四次挥手关闭连接

1.为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?
这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的连接请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可能未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。

2.为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?
这个问题可以参考《unix 网络编程》(第三版,2.7 TIME_WAIT状态)。
TIME_WAIT状态由两个存在的理由。
(1)可靠的实现TCP全双工链接的终止。
这是因为虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。
(2)允许老的重复的分节在网络中消逝。
假设在12.106.32.254的1500端口和206.168.1.112.219的21端口之间有一个TCP连接。我们关闭这个链接,过一段时间后在相同的IP地址和端口建立另一个连接。后一个链接成为前一个的化身。因为它们的IP地址和端口号都相同。TCP必须防止来自某一个连接的老的重复分组在连接已经终止后再现,从而被误解成属于同一链接的某一个某一个新的化身。为做到这一点,TCP将不给处于TIME_WAIT状态的链接发起新的化身。既然TIME_WAIT状态的持续时间是MSL的2倍,这就足以让某个方向上的分组最多存活msl秒即被丢弃,另一个方向上的应答最多存活msl秒也被丢弃。通过实施这个规则,我们就能保证每成功建立一个TCP连接时。来自该链接先前化身的重复分组都已经在网络中消逝了。

3. 为什么不能用两次握手进行连接?
我们知道,3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。
    现在把三次握手改成仅需要两次握手,死锁是可能发生的。作为例子,考虑计算机S和C之间的通信,假定C给S发送一个连接请求分组,S收到了这个分组,并发 送了确认应答分组。按照两次握手的协定,S认为连接已经成功地建立了,可以开始发送数据分组。可是,C在S的应答分组在传输中被丢失的情况下,将不知道S 是否已准备好,不知道S建立什么样的序列号,C甚至怀疑S是否收到自己的连接请求分组。在这种情况下,C认为连接还未建立成功,将忽略S发来的任何数据分 组,只等待连接确认应答分组。而S在发出的分组超时后,重复发送同样的分组。这样就形成了死锁。

补充:
a. 默认情况下(不改变socket选项),当你调用close( or closesocket,以下说close不再重复)时,如果发送缓冲中还有数据,TCP会继续把数据发送完。
b. 发送了FIN只是表示这端不能继续发送数据(应用层不能再调用send发送),但是还可以接收数据。
c. 应用层如何知道对端关闭?通常,在最简单的阻塞模型中,当你调用recv时,如果返回0,则表示对端关闭。在这个时候通常的做法就是也调用close,那么TCP层就发送FIN,继续完成四次握手。如果你不调用close,那么对端就会处于FIN_WAIT_2状态,而本端则会处于CLOSE_WAIT状态。这个可以写代码试试。
d. 在很多时候,TCP连接的断开都会由TCP层自动进行,例如你CTRL+C终止你的程序,TCP连接依然会正常关闭,你可以写代码试试。

插曲:
   特别的TIME_WAIT状态:

   从以上TCP连接关闭的状态转换图可以看出,主动关闭的一方在发送完对对方FIN报文的确认(ACK)报文后,会进入TIME_WAIT状态。TIME_WAIT状态也称为2MSL状态。

   什么是2MSL?MSL即Maximum Segment Lifetime,也就是报文最大生存时间,引用《TCP/IP详解》中的话:“它(MSL)是任何报文段被丢弃前在网络内的最长时间。”那么,2MSL也就是这个时间的2倍。其实我觉得没必要把这个MSL的确切含义搞明白,你所需要明白的是,当TCP连接完成四个报文段的交换时,主动关闭的一方将继续等待一定时间(2-4分钟),即使两端的应用程序结束。你可以写代码试试,然后用setstat查看下。

   为什么需要2MSL?根据《TCP/IP详解》和《The TCP/IP Guide》中的说法,有两个原因:
   其一,保证发送的ACK会成功发送到对方,如何保证?我觉得可能是通过超时计时器发送。这个就很难用代码演示了。
   其二,报文可能会被混淆,意思是说,其他时候的连接可能会被当作本次的连接。直接引用《The TCP/IP Guide》的说法:The second is to provide a “buffering period” between the end of this connection and any subsequent ones. If not for this period, it is possible that packets from different connections could be mixed, creating confusion.

   TIME_WAIT状态所带来的影响:
   当某个连接的一端处于TIME_WAIT状态时,该连接将不能再被使用。事实上,对于我们比较有现实意义的是,这个端口将不能再被使用。某个端口处于TIME_WAIT状态(其实应该是这个连接)时,这意味着这个TCP连接并没有断开(完全断开),那么,如果你bind这个端口,就会失败。对于服务器而言,如果服务器突然crash掉了,那么它将无法再2MSL内重新启动,因为bind会失败。解决这个问题的一个方法就是设置socket的SO_REUSEADDR选项。这个选项意味着你可以重用一个地址。

   对于TIME_WAIT的插曲:
   当建立一个TCP连接时,服务器端会继续用原有端口监听,同时用这个端口与客户端通信。而客户端默认情况下会使用一个随机端口与服务器端的监听端口通信。有时候,为了服务器端的安全性,我们需要对客户端进行验证,即限定某个IP某个特定端口的客户端。客户端可以使用bind来使用特定的端口。对于服务器端,当设置了SO_REUSEADDR选项时,它可以在2MSL内启动并listen成功。但是对于客户端,当使
用bind并设置SO_REUSEADDR时,如果在2MSL内启动,虽然bind会成功,但是在windows平台上connect会失败。而在linux上则不存在这个问题。(我的实验平台:winxp, ubuntu7.10)
    要解决windows平台的这个问题,可以设置SO_LINGER选项。SO_LINGER选项决定调用close时TCP的行为。SO_LINGER涉及到linger结构体,如果设置结构体中l_onoff为非0,l_linger为0,那么调用close时TCP连接会立刻断开,TCP不会将发送缓冲中未发送的数据发送,而是立即发送一个RST报文给对方,这个时候TCP连接就不会进入TIME_WAIT状态。如你所见,这样做虽然解决了问题,但是并不安全。通过以上方式设置SO_LINGER状态,等同于设置SO_DONTLINGER状态。

    断开连接时的意外:
    这个算不上断开连接时的意外,当TCP连接发生一些物理上的意外情况时,例如网线断开,linux上的TCP实现会依然认为该连接有效,而windows则会在一定时间后返回错误信息。这似乎可以通过设置SO_KEEPALIVE选项来解决,不过不知道这个选项是否对于所有平台都有效。
分享到:
评论

相关推荐

    TCP-IP详解卷一:协议_TCP-IP详解_TCP/IP_tcp/ip详解_

    TCP通过三次握手建立连接,确保双方都有发送和接收能力。在数据传输过程中,TCP使用滑动窗口机制进行流量控制,防止拥塞,并通过确认和重传机制保证数据的可靠性。 IP(Internet Protocol)则是网络层的主要协议,...

    TCP-IP详解卷1 /斯蒂文斯TCP IP

    7. **TCP协议**:深入探讨TCP的连接建立、数据传输、流量控制、拥塞控制、断开连接等机制,包括三次握手、四次挥手等经典过程。 8. **TCP连接管理**:分析TCP连接的建立与终止,以及滑动窗口协议,确保数据的正确...

    Wireshark抓包分析微信功能----tcp/ip选修课期末大作业

    TCP通过三次握手建立连接,确保双方准备好通信。而在数据传输后,四次挥手释放连接,保证资源的有效利用。在TCP中,每个数据包都有一个序列号和确认号,用于跟踪数据包的正确顺序和接收。 IP协议则主要负责网络层的...

    TCP.UDP_gaojibiancheng.rar_TCP-UDP_c# tcp/udp_tcp/udp_visual c

    1. **TCP编程基础**:包括TCP连接的建立(三次握手)、数据传输、连接终止(四次挥手)以及异常处理。 2. **TCP套接字编程**:讲解C#的System.Net.Sockets命名空间下的TcpClient和TcpListener类,以及Visual C++中...

    TCP-IP技术大全1.rar_TCP/IP_μC/TCP-IP

    TCP是TCP/IP协议栈中的关键组件,它通过三次握手建立连接,并采用滑动窗口机制进行流量控制和拥塞避免,确保数据的可靠传输。而IP协议则是无连接的,主要负责将数据包发送到目的地,不保证数据的顺序或完整性,这些...

    TCP-UDP程序 _TCP/UDP通信程序_

    在TCP通信开始前,需要先建立连接,这个过程称为三次握手。一旦连接建立,双方可以进行数据传输。TCP通过序列号和确认应答机制确保数据的正确性,同时使用滑动窗口和重传机制来控制流量和处理丢失的数据。TCP服务器...

    UDP-TCP.rar_TCP UDp_TCP-UDP_tcp/udp socket_网络UDP TCP

    TCP是一种面向连接的、可靠的协议,它在数据传输前会建立连接,通过三次握手确保两端的通信。在数据传输过程中,TCP使用序列号和确认应答机制,确保数据的正确性和完整性。此外,TCP还有流量控制和拥塞控制机制,...

    TCP报文分析--三次握手 四次挥手

    TCP 报文分析--三次握手四次挥手 TCP 报文分析是计算机网络中的重要内容, TCP(Transmission Control Protocol)是一种面向连接的传输控制协议,它提供了可靠的数据传输服务。在这个过程中,三次握手和四次挥手是 ...

    TCP-UDP服务管理 3.01

    它确保了数据的完整性和顺序,通过三次握手建立连接,通过序列号和确认应答机制确保数据无丢失或重复,还通过流量控制和拥塞控制来优化网络资源的使用。TCP通常用于需要高可靠性的应用,如HTTP、HTTPS、FTP、SMTP等...

    tcp-udp.rar_TCP程序_delphi tcp 通讯_delphi tcp/ip_tcp-udp delphi_tcp

    1. 面向连接:在数据传输前,TCP需要先建立连接,通过三次握手确保双方都有能力进行通信。 2. 可靠性:TCP提供了序列号和确认机制,确保数据包按照发送顺序到达,并且丢失的数据包能够被重新发送。 3. 流量控制:...

    TCP-UDP连接断开程序.zip

    当两台设备建立TCP连接时,它们会经历三次握手的过程,确保双方都能正常通信。而在通信结束后,通过四次挥手来断开连接,释放资源。TCP连接的状态包括SYN_SENT、SYN_RCVD、ESTABLISHED、FIN_WAIT_1、FIN_WAIT_2、...

    TCP-UDP服务管理 V3.01

    例如,通过查看TCP连接的三次握手和四次挥手过程,可以诊断连接问题;通过分析UDP的数据包发送和接收,可以找出可能的丢包原因。 数据日志记录功能是另一个亮点。它允许开发者保存网络通信过程中的详细信息,便于...

    TCP-UDP数据包自动发送工具V3.01版本

    TCP是一种面向连接的、可靠的协议,它确保了数据的有序和无损传输,通过三次握手建立连接,并使用确认、重传和流量控制机制来保证数据的可靠性。而UDP则是一种无连接的、不可靠的协议,它不保证数据包的顺序和到达,...

    TCP三次握手与四次挥手.pdf

    为了实现可靠的连接,TCP采用了三次握手(建立连接)和四次挥手(断开连接)的过程。这两个过程是确保数据传输前建立连接与传输后释放连接的关键机制。 首先,来详细介绍TCP三次握手的过程: 1. 第一次握手:...

    tcp3次握手建立连接 4次握手关闭连接

    TCP是一个面向连接的协议,所以在连接双方发送数据之前,都需要首先建立一条连接。TCP连接的建立可以简单的称为三次握手,而连接的中止则可以叫做四次握手。

    wireshark抓包分析tcp三次握手四次挥手详解及网络命令

    ### Wireshark抓包分析TCP三次握手四次挥手详解及网络命令 #### 一、OSI与TCP/IP体系结构模型 在深入理解Wireshark抓包分析TCP三次握手及四次挥手之前,我们首先需要了解OSI七层模型与TCP/IP四层/五层模型的基础...

    TCP-TIMEOUT.rar_ tcp timeo_CFG TCP/IP TIMEOUT_TCP 超时_超时三次

    3. 第三次握手:最后,客户端再发送一个ACK数据段,确认收到服务器的SYN+ACK,至此,连接建立完成。 TCP超时是TCP协议中的一种重要机制,用于处理网络延迟、丢包等问题。当TCP数据包在网络中传输时,如果超过了预设...

    wireshark抓包分析tcp三次握手四次挥手

    4. **第四次挥手**:Client接收到FIN后,发送一个ACK报文作为回应,确认收到关闭连接的通知。至此,四次挥手完成,连接正式关闭。 在HTTP协议中,TCP连接通常被用于传输HTTP报文。HTTP是基于TCP的,因此在Wireshark...

    TCP-IP技术大全(TCP/IP的参考资料)

    例如,TCP的三次握手和四次挥手过程,确保了连接的建立和断开。IP的子网掩码和CIDR(Classless Inter-Domain Routing)用于划分网络和分配地址。同时,还需要掌握TCP/IP的配置、网络故障排查以及网络安全相关的知识...

    TCP-UDP-RS232调试助手.rar

    它确保了数据包的顺序传输和错误检测,通过三次握手建立连接,四次挥手断开连接。在软件开发中,TCP常用于需要高可靠性的应用,如文件传输、电子邮件等。 UDP(User Datagram Protocol)用户数据报协议则是一种无...

Global site tag (gtag.js) - Google Analytics