主要部分,四次握手:
断开连接其实从我的角度看不区分客户端和服务器端,任何一方都可以调用close(or closesocket)之类
的函数开始主动终止一个连接。这里先暂时说正常情况。当调用close函数断开一个连接时,主动断开的
一方发送FIN(finish报文给对方。有了之前的经验,我想你应该明白我说的FIN报文时什么东西。也就是
一个设置了FIN标志位的报文段。FIN报文也可能附加用户数据,如果这一方还有数据要发送时,将数据附
加到这个FIN报文时完全正常的。之后你会看到,这种附加报文还会有很多,例如ACK报文。我们所要把握
的原则是,TCP肯定会力所能及地达到最大效率,所以你能够想到的优化方法,我想TCP都会想到。
当被动关闭的一方收到FIN报文时,它会发送ACK确认报文(对于ACK这个东西你应该很熟悉了)。这里有个
东西要注意,因为TCP是双工的,也就是说,你可以想象一对TCP连接上有两条数据通路。当发送FIN报文
时,意思是说,发送FIN的一端就不能发送数据,也就是关闭了其中一条数据通路。被动关闭的一端发送
了ACK后,应用层通常就会检测到这个连接即将断开,然后被动断开的应用层调用close关闭连接。
我可以告诉你,一旦当你调用close(or closesocket),这一端就会发送FIN报文。也就是说,现在被动
关闭的一端也发送FIN给主动关闭端。有时候,被动关闭端会将ACK和FIN两个报文合在一起发送。主动
关闭端收到FIN后也发送ACK,然后整个连接关闭(事实上还没完全关闭,只是关闭需要交换的报文发送
完毕),四次握手完成。如你所见,因为被动关闭端可能会将ACK和FIN合到一起发送,所以这也算不上
严格的四次握手---四个报文段。
在前面的文章中,我一直没提TCP的状态转换。在这里我还是在犹豫是不是该将那张四处通用的图拿出来,
不过,这里我只给出断开连接时的状态转换图,摘自<The TCP/IP Guide>:
给出一个正常关闭时的windump信息:
14:00:38.819856 IP cd-zhangmin.1748 > 220.181.37.55.80: F 1:1(0) ack 1 win 65535
14:00:38.863989 IP 220.181.37.55.80 > cd-zhangmin.1748: F 1:1(0) ack 2 win 2920
14:00:38.864412 IP cd-zhangmin.1748 > 220.181.37.55.80: . ack 2 win 65535
补充细节:
关于以上的四次握手,我补充下细节:
1. 默认情况下(不改变socket选项),当你调用close( or closesocket,以下说close不再重复)时,如果
发送缓冲中还有数据,TCP会继续把数据发送完。
2. 发送了FIN只是表示这端不能继续发送数据(应用层不能再调用send发送),但是还可以接收数据。
3. 应用层如何知道对端关闭?通常,在最简单的阻塞模型中,当你调用recv时,如果返回0,则表示对端
关闭。在这个时候通常的做法就是也调用close,那么TCP层就发送FIN,继续完成四次握手。如果你不调用
close,那么对端就会处于FIN_WAIT_2状态,而本端则会处于CLOSE_WAIT状态。这个可以写代码试试。
4. 在很多时候,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分钟),即使两端的应用程序结束。你可以写代码试试,然后用netstat查看下。
为什么需要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多连接的建立与断开,主要关注TCP连接中的Socket对象管理和稳妥断开机制。TCP(Transmission Control Protocol)是一种面向连接的、可靠的传输层协议,它确保了数据的完整性和顺序。在多连接...
1. **三次握手**:当两个主机想要建立TCP连接时,必须经过三次交互。首先,客户端发送一个SYN(同步序列编号)段给服务器,请求建立连接。服务器接收到后,回复一个SYN+ACK段,确认并同步序列号。最后,客户端再发送...
9. **TCP/IP配置**:了解TCP/IP协议的工作原理,例如熟知的三次握手和四次挥手过程,有助于理解为何有时候需要手动关闭TCP连接。 掌握这些方法和知识,有助于你在遇到需要强制结束TCP连接的情况时,能够迅速有效地...
TCP状态转移图详细描述了TCP连接从建立到结束的整个过程,包括CLOSED(起始状态)、LISTEN(服务端等待连接状态)、SYN_SENT(客户端发起连接状态)、SYN_RCVD(服务器接收客户端的SYN请求状态)等不同状态及其转移...
2. **TCP状态迁移图**:描述了TCP连接建立、数据传输和关闭的过程。三次握手和四次挥手是其中的关键步骤。 - **三次握手**:确保连接建立时双方都准备好进行通信。 - **数据传输**:在连接建立后,双方可以开始...
- **连接管理**:服务器需要跟踪每个客户端连接的状态,以便在必要时断开连接或处理多个并发连接。 3. **掉线查询与重连策略**:为了实现“掉线查询”和“掉线重连”,我们需要在客户端和服务器端都加入心跳机制。...
7. **状态管理**:维护TCP连接的状态,如连接、断开、等待等,以便正确处理各种交互。 在压缩包中的“TCP”文件可能是源代码、项目文件或其他相关资源。为了更深入地学习和理解这个VB TCP项目,你需要打开这些文件...
1. **TCP通信基础**:LabVIEW提供了丰富的TCP/IP函数库,如`TCP Open.vi`用于建立连接,`TCP Write.vi`用于发送数据,`TCP Read.vi`用于接收数据,以及`TCP Close.vi`用于关闭连接。理解这些函数的工作原理是进行TCP...
该程序提供了一个用户友好的图形用户界面,允许用户输入服务器的IP地址和端口号,并可以通过连接和断开连接按钮控制与服务器的连接状态。用户还可以在发送数据框中输入要发送的消息,并通过发送按钮将其发送给服务器...
TCP连接的建立和断开通常遵循三次握手(Three-Way Handshake)的过程: 1. 客户端发送SYN段,请求连接,设置序号为X。 2. 服务器响应SYN+ACK段,确认序号为X+1,设置自己的序号为Y,表明同意连接并提出自己的连接...
【TCP报头协议实验】是针对计算机网络中的TCP(传输控制协议)进行深入理解的实践操作,主要关注TCP连接的建立、数据交换以及连接的拆除过程。实验涉及到的关键概念包括ACK(确认序列号)、序号(Sequence Number)...
2. **连接与断开**:通过“打开TCP连接”和“关闭TCP连接”函数,可以建立和断开客户端与服务器之间的连接。 3. **数据发送与接收**:使用“写TCP”函数将数据发送到TCP连接,而“读TCP”函数则用于从连接读取数据...
EMWIN显示并发TCP客户端连接是将嵌入式GUI库EMWIN与轻量级网络协议栈LWIP结合的实例,用于在嵌入式系统中实现图形化的网络连接管理。这个实验程序的核心目标是通过EMWIN的图形界面动态展示当前与服务器建立TCP连接的...
这些工具对于系统管理员、网络工程师以及IT专业人员来说非常有用,因为它们能够提供关于哪些进程正在与远程主机进行通信、连接的端口号、状态(如监听、已建立、关闭等待等)以及相关IP地址的详细信息。 在提供的...
与TCP不同,UDP是无连接的、不可靠的协议,适合对实时性要求高的场景。在C#中,我们可以使用`UdpClient`类来实现UDP通信。 对于UDP通信: 1. 创建`UdpClient`实例,指定本地端口号。 2. 使用`Receive()`方法接收...
在LabVIEW编程环境中,TCP(Transmission Control Protocol)是一种常用的数据通信协议,用于在不同设备间建立可靠的、面向连接的数据传输。本示例“TCP-image-TRS.zip”专注于使用LabVIEW进行TCP图片传输,即发送和...
在TCP连接中,心跳包可以定期发送,如果一段时间内没有收到对方的回应,就可以认为连接已断开。在C#的Socket编程中,可以设定一个定时器,周期性地发送心跳包,并监听返回的响应,确保连接的稳定。 3. **TCP/IP协议...
例如,文件`tcp_teardown.pcapng`就是一个记录了TCP断开连接过程的网络流量文件。在Wireshark中打开此文件,可以清晰地看到每个阶段的数据包细节,包括源IP、目的IP、序列号、确认号以及各个标志位的状态,从而深入...