TCP连接——爱的传声筒

TCP连接——爱的传声筒

TCP通信最重要的特征是:有序(ordering)和可靠(reliable)。有序是通过将文本流分段并编号实现的。可靠是通过ACK回复和重复发送(retransmission)实现的。这一篇文章将引入TCP连接(connection)的概念。

TCP连接

网络层在逻辑上提供了端口的概念。一个IP地址可以有多个端口。一个具体的端口需要IP地址和端口号共同确定(我们记为IP:port的形式)。一个连接为两个IP:port之间建立TCP通信。(一个常用的比喻为:TCP连接就像两个人打电话, IP为总机号码,port为分机号码)

参与连接的如果是两台电脑,那么两台电脑操作系统的TCP模块负责建立连接。每个连接有四个参数(两个IP,两个端口),来表明“谁在和谁通话”。每台电脑都会记录有这四个参数,以确定是哪一个连接。如果这四个参数完全相同,则为同一连接;如果这四个参数有一个不同,即为不同的连接。这意味着,同一个端口上可以有多个连接。内核中的TCP模块生成连接之后,将连接分配给进程使用。

一个端口上可以有多个连接

TCP连接是双向(duplex)的。在TCP协议与"流"通信中,我们所展示的TCP传输是单向的。双向连接实际上就是建立两个方向的TCP传输,所以概念上并不复杂。这时,连接的每一方都需要两个滑窗,以分别处理发送的文本流和接收的文本流。由于连接的双向性,我们也要为两个方向的文本流编号。这两个文本流的编号相互独立。为文本流分段和编号由发送方来处理,回复ACK则由接收的一方进行。

TCP片段的头部格式

在深入TCP连接之前,我们需要对TCP片段的头部格式有一些了解。我们知道,TCP片段分为头部和数据。数据部分为TCP真正传输的文本流数据。下面为TCP片段的头部格式:

来自wikipedia

先关注下面几点:

1. 一个TCP头部需要包含出发端口(source port)和目的地端口(destination port)。这些与IP头中的两个IP地址共同确定了连接。

2. 每个TCP片段都有序号(sequence number)。这些序号最终将数据部分的文本片段整理成为文本流。

3. ACK是一位(bit)。只有ACK位设定的时候,回复号(Acknowledgement number)才有效。ACK回复号说明了接收方期待接收的下一个片段,所以ACK回复号为最后接收到的片段序号加1。

很多时候,ACK回复“附着”在发送的数据片段中。TCP协议是双向的。比如A和B两个电脑。ACK回复是接收方回复给发送方 (比如A发送给B, B回复A)。但同时,B也可以是发送方,B有可能有数据发送给A,所以B就把ACK回复附着在它要发送给A的数据片段的头部。这样可以减少ACK所占用的交通流量。一个片段可以只包含ACK回复。一个纯粹的ACK回复片段不传送文本流,所以不消耗序列号。如果有下一个正常的数据片段,它的序号将与纯粹ACK回复片段的序号相同。

(ACK回复还可以“附着”在SYN片段和FIN片段)

4. ACK后面还有SYN和FIN,它们也各占据一位(bit)。我将在后面说明这两位。

连接的建立

在TCP协议与"流"通信中讨论的TCP传输需要一个前提:TCP连接已经建立。然而,TCP连接从无到有需要一个建立连接的过程。建立连接的最重要目是让连接的双方交换初始序号(ISN, Initial Sequence Number)。根据TCP协议的规定,文本流的第一个片段的序号不能是确定的数字(比如说1)。连接的双方各自随机生成自己的ISN,然后再利用的一定方式让对方了解。这样的规定是出于TCP连接安全考虑:如果以一个确定的数字作为初始的TCP序号,那么其他人很容易猜出接下来的序列号,并按照正确的序号发送“伪装”的TCP片段,以插入到文本流中。

ISN交换是通过SYN片段实现的。SYN片段由头部的SYN位表明,它的序号为发送方的ISN。该片段由连接的一方首先发给给另一方,我们将发送SYN的一方称为客户(client),而接收SYN的一方称为服务器(server)。我们使用ISN(c)表示client一方的ISN,使用ISN(s)表示server一方的ISN。随后,接收到SYN的server需要回复ACK,并发送出包含有server的ISN的SYN片段。下图为建立连接的过程,也就是经典的TCP三次握手(three-way handshaking)。两条竖直线分别为client和server的时间轴。每个箭头代表了一次TCP片段的单向传输。

青色为纯粹的ACK片段。整个过程的本质是双方互发含有自己的ISN的SYN片段。根据TCP传输的规则,接收到ISN的一方需要回复ACK,所以共计四片信息在建立连接过程中传输。之所以是三次握手 (而不是四次),是因为server将发送SYN和回复ACK合并到一个TCP片段中。我们以client方为例。client知道自己的ISN(也就是ISN(c))。建立连接之后,它也知道了对方的ISN(s)。此后,如果需要发送文本流片段,则编号为ISN(c) + 1, ISN(c) + 2 ...。如果接收文本流片段,则期待接收ISN(s) + 1, ISN(s) + 2 ...。

连接建立之后,连接的双方就可以按照TCP传输的方式相互发送文本流了。

连接的正常终结

一个连接建立之后,连接两端的进程可以利用该连接进行通信。当连接的一方觉得“我讲完了”,它可以终结连接中发送到对方方向的通信。连接最终通过四次握手(four-way handshaking)的方式终结,连接终结使用的是特殊片段FIN(FIN位为1的片段)。

我们可以看到,连接终结的过程中,连接双方也交换了四片信息(两个FIN和两个ACK)。在终结连接的过程中,TCP并没有合并FIN与ACK片段。原因是TCP连接允许单向关闭(half-close)。也就是说,TCP连接关闭了一个方向的传输,成为一个单向连接(half-duplex)。第二个箭头和第三个箭头传递必须分开,才能有空隙在开放的方向上继续传输。如果第二个箭头和第三个箭头合并在一起,那么,随着一方关闭,另一方也要被迫关闭。

第二和第三次握手之间,server可以继续单向的发送片段给client,但client不能发送数据片段给server。

(上面的终结从client先发起,TCP连接终结也可以从server先发起。)

在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。

TIME_WAIT State

总结

TCP是连接导向的协议,与之对应的是像UDP这样的非连接导向的协议。连接能带来更好的传输控制,但也需要更多额外的工作,比如连接的建立和终结。

我们还初步了解了TCP的头部格式。应该注意到,许多时候我们将ACK片段“附着”在其他片段上。相对于纯粹的ACK片段,我们这样做节约了ACK所需的流量。事实上,由于ACK片段所需的ACK位和acknowledge number区域总是存在于TCP的头部,所以附着ACK片段的成本基本上等于0。

时间: 2025-01-02 03:53:17

TCP连接——爱的传声筒的相关文章

如何在socket编程的Tcp连接中实现心跳协议

心跳包的发送,通常有两种技术 方法1:应用层自己实现的心跳包 由应用程序自己发送心跳包来检测连接是否正常,大致的方法是:服务器在一个 Timer事件中定时 向客户端发送一个短小精悍的数据包,然后启动一个低级别的线程,在该线程中不断检测客户端的回应, 如果在一定时间内没有收到客户端的回应,即认为客户端已经掉线:同样,如果客户端在一定时间内没 有收到服务器的心跳包,则认为连接不可用. 方法2:TCP的KeepAlive保活机制 因为要考虑到一个服务器通常会连接多个客户端,因此由用户在应用层自己实现心

TCP连接的状态详解以及故障排查

转载自CSDN博客:http://blog.csdn.net/hguisu/article/details/38700899 TCP状态 TCP状态迁移路线图 TCP连接建立三次握手 TCP连接的终止四次握手释放 同时打开 同时关闭 TCP通信中服务器处理客户端意外断开 Linux错误信息errno列表 我们通过了解TCP各个状态,可以排除和定位网络或系统故障时大有帮助.(总结网络上的内容) 1.TCP状态 了解TCP之前,先了解几个命令:   linux查看tcp的状态命令: 1).netst

解决不对称流量经过JUNIPER防火墙,tcp连接重置丢失问题

背景:公司网络增加一台JUNIPER防火墙,用于外网网关使用,其实配置上网配置很简单,配置完成后,外网连接测试也都正常,但在特殊的测试环境中会出现一种情况,该环境如图所示: 现象:当PC机的网关指定为防火墙的内网接口后(而不是核心交换机地址),当pc在telnet或者ssh连接10.10.2.*网段的服务器(网关在核心交换机上)等时,tcp连接均会在20s后重置.我的环境中其实存在一些问题的,就是流经防火墙的流量并不对称,其中pc→服务器的流量经过防火墙,而服务器→pc的流量不经过防火墙,造成的

TCP连接状态及TIME_WAIT

参考: TCP连接中的TIME_WAIT状态 - sunnydogzhou的专栏 - 博客频道 - CSDN.NET http://blog.csdn.net/sunnydogzhou/article/details/6572071 TCP连接状态详解及TIME_WAIT过多的解决方法_小强_新浪博客 http://blog.sina.com.cn/s/blog_8e5d24890102w9yi.html TCP协议三次握手连接四次握手断开和DOS攻击 - NowOrNever - 博客频道 -

TCP连接检测机制

采用TCP连接的C/S模式软件,连接的双方在连接空闲状态时,如果任意一方意外崩溃.当机.网线断开或路由器故障,另一方无法得知TCP连接已经失效,除非继续在此连接上发送数据导致错误返回.很多时候,这不是我们需要的.我们希望服务器端和客户端都能及时有效地检测到连接失效,然后优雅地完成一些清理工作并把错误报告给用户. 客户端采用如下步骤: 1, 连接 2, 拔掉网线 经过以上两步: 从上图中可以看到,此时服务端的连接依然存在. 所以,tcp只是数据的发送与接收,包括握手,断开以及rst,time_wa

服务器后台TCP连接存活问题

0. 背景 公司的服务器后台部署在某一个地方,接入的是用户的APP,而该地方的网络信号较差,导致了服务器后台在运行一段时间后用户无法接入,那边的同事反馈使用netstat查看系统,存在较多的TCP连接. 1. 问题分析 首先在公司内部测试服务器上部署,使用LoadRunner做压力测试,能正常运行,然后那边的同事反馈该地方信号较差.考虑到接入的问题,有可能接入进程的FD资源耗尽,导致accept失败.推论的依据是对于TCP连接来说,如果客户端那边由于一些异常情况导致断网而未能向服务器发起FIN关

TCP 连接与TCP keep alive 保活检测机制

生产环境中一台2核4G的linux服务器TCP连接数时常保持在5-7w间徘徊,查看日志每秒的请求数也就100-200,怎么会产生这么大的TCP连接数.检查了下客户端上行的HTTP协议,Connection 头字段是Keep-Alive,并且客户端在请求完之后没有立即关闭连接.而服务端的设计也是根据客户端来的,客户端上行如果Connection:Keep-Alive,服务端是不会主动关闭连接的.在客户端与服务端交互比较频繁的时候,这样的设计还是比较合理的,可以减少TCP的重复握手.显然如果只交互一

socket连接和TCP连接的关系

我们在传输数据时,可以只使用(传输层)TCP/IP协议,但是那样的话,如果没有应用层,便无法识别数据内容,如果想要使传输的数据有意义,则必须使用到应用层协议,应用层协议有很多,比如HTTP.FTP.TELNET等,也可以自己定义应用层协议.WEB使用HTTP协议作应用层协议,以封装HTTP文本信息,然后使用TCP/IP做传输层协议将它发到网络上. 1)Socket是一个针对TCP和UDP编程的接口,你可以借助它建立TCP连接等等.而TCP和UDP协议属于传输层 . 而http是个应用层的协议,它

tcp连接、断开过程

TIME_WAIT状态在等2MSL后closed,存在的原因:1.ack n+1可能丢失,FIN N超时重发,如果不存在time_wait状态,则C端下次收到会响应RST报文,S端收到则会解释为是错误.因而,要实现TCP全双工连接的正常终止,必须正确处理终止过程中四个分节任何一个分节的丢失情况,主动关闭连接的A端必须维持TIME_WAIT状态 . 2.允许老的重复分节在网络中消失(消失前不允许启动新的化身).比如在没消失前启动一个新连接,那么老连接的一些报文可能在新连接的时候到来,这个时候就会发