本文内容来自《TCP/IP详解卷1:协议》
17.2 TCP的服务
T C P提供一种面向连接的、可靠的字节流服务。
面向连接意味着两个使用 T C P的应用(通常是一个客户和一个服务器)在彼此交换数据之前必须先建立一个 T C P连接。这一过程与打电话很相似,先拨号振铃,等待对方摘机说“喂”,然后才说明是谁。
T C P通过下列方式来提供可靠性:
-
应用数据被分割成T C P认为最适合发送的数据块。这和 U D P完全不同,应用程序产生的数据报长度将保持不变。由 T C P传递给I
P的信息单位称为报文段或段( s e g m e n t)。 -
当T C P发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。
-
当T C P收到发自T C P连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常将推迟几分之一秒,这将在1 9 . 3节讨论。
-
T C P将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错, T C
P将丢弃这个报文段和不确认收到此报文段(希望发端超时并重发)。 -
既然T C P报文段作为I P数据报来传输,而I P数据报的到达可能会失序,因此 T C P报文段的到达也可能会失序。如果必要, T C
P将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层。 -
既然I P数据报会发生重复,T C P的接收端必须丢弃重复的数据。
-
T C P还能提供流量控制。 T C P连接的每一方都有固定大小的缓冲空间。 TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲区溢出。
17.3 TCP的首部
每个T C P段都包含源端和目的端的端口号,用于寻找发端和收端应用进程。这两个值加上I P首部中的源端I P地址和目的端I P地址唯一确定一个T C P连接。
18.2 连接的建立与终止
18.2.1 t c p d u m p的输出
18.2.3 建立连接协议
现在让我们回到图1 8 - 3所示的T C P协议中来。为了建立一条T C P连接:
18.2.4 连接终止协议
18.2.5 正常的t c p d u m p输出
18.3 连接建立的超时
18.4 最大报文段长度
最大报文段长度(M S S)表示T C P传往另一端的最大块数据的长度。对于一个以太网,M S S值可达1 4 6 0字节。
18.5 TCP的半关闭
T C P提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。这就是所谓的半关闭。
为什么要有半关闭?
书上的例子总结来说就是,A主机向B主机发一系列数据,让B主机排好序之后把数据发给A。那么B主机怎么知道A主机已经把待排序的数据发完了呢?半关闭就可以解决这个问题哦。传完后A发FIN给B,就代表传完了。
18.6 TCP的状态变迁图
(1)在这个图中要注意的第一点是一个状态变迁的子集是“典型的”。我们用粗的实线箭头表示正常的客户端状态变迁,用粗的虚线箭头表示正常的服务器状态变迁。
(2)第二点是两个导致进入E S TA B L I S H -E D状态的变迁对应打开一个连接,而两个导致从E S TA B L I S H E D状态离开的变迁
对应关闭一个连接。E S TA B L I S H E D状态是连接双方能够进行双向数据传递的状态。以后的章节将介绍这个状态。
18.6.1 2MSL等待状态
本节参考博文地址:
https://blog.csdn.net/sinat_35297665/article/details/80979181
https://blog.csdn.net/tennysonsky/article/details/48680197
为什么要等待2MSL?
- 1、为了保证客户端发送的最后一个ACK报文段能够到达服务器。因为这个ACK有可能丢失,从而导致处在LAST-ACK状态的服务器收不到对FIN-ACK的确认报文。服务器会超时重传这个FIN-ACK,接着客户端再重传一次确认,重新启动时间等待计时器。最后客户端和服务器都能正常的关闭。假设客户端不等待2MSL,而是在发送完ACK之后直接释放关闭,一但这个ACK丢失的话,服务器就无法正常的进入关闭连接状态。
- 2、他还可以防止已失效的报文段。客户端在发送最后一个ACK之后,再经过经过2MSL,就可以使本链接持续时间内所产生的所有报文段都从网络中消失。从保证在关闭连接后不会有还在网络中滞留的报文段去骚扰服务器。
(TCP分节可能由于路由器异常而“迷途”,在迷途期间,TCP发送端可能因确认超时而重发这个分节,迷途的分节在路由器修复后也会被送到最终目的地,这个原来的迷途分节就称为lost duplicate。在关闭一个TCP连接后,马上又重新建立起一个相同的IP地址和端口之间的TCP连接,后一个连接被称为前一个连接的化身(incarnation),那么有可能出现这种情况,前一个连接的迷途重复分组在前一个连接终止后出现,从而被误解成从属于新的化身。为了避免这个情况,TCP不允许处于TIME_WAIT状态的连接启动一个新的化身,因为TIME_WAIT状态持续2MSL,就可以保证当成功建立一个TCP连接的时候,来自连接先前化身的重复分组已经在网络中消逝。)
RST标志位
本节参考博文地址:https://blog.csdn.net/erlib/article/details/50132307
RST表示复位,用来异常的关闭连接,在TCP的设计中它是不可或缺的。就像上面说的一样,发送RST包关闭连接时,不必等缓冲区的包都发出去(不像上面的FIN包),直接就丢弃缓存区的包发送RST包。而接收端收到RST包后,也不必发送ACK包来确认。
TCP处理程序会在自己认为的异常时刻发送RST包。例如,A向B发起连接,但B之上并未监听相应的端口,这时B操作系统上的TCP处理程序会发RST包。
又比如,AB正常建立连接了,正在通讯时,A向B发送了FIN包要求关连接,B发送ACK后,网断了,A通过若干原因放弃了这个连接(例如进程重启)。网通了后,B又开始发数据包,A收到后表示压力很大,不知道这野连接哪来的,就发了个RST包强制把连接关了,B收到后会出现connect reset by peer错误。
18.8 同时打开
18.9 同时关闭
第19章 TCP的交互数据流
Nagle算法
这节来自于下面博客地址:
https://blog.csdn.net/zxm342698145/article/details/80992532
有以下一个场景,村东和村西隔着一条大河,有几条船在两岸摆渡。由于每次要求过河的人只有一个,如果来一个人就将那个人摆渡过去(假设船只足够多),那势必运输效率非常低,而且大大浪费运输资源。可是过河人想尽快过河,而摆渡人又想多等几个人一起过河,于是尴尬的局面出现了,摆渡人与等船人经常在等船时间上发生争执。后来大家约定了发船的时间,前面那条船摆过去并返回之后,后面一条才发船,无论船上有多少人(没人肯定不算)。大家都觉得这个方案不错,在人数和等待发船的时间上达到了平衡,这才停止了矛盾的发生。
nagle算法实际上就是上面场景的体现。
在使用一些协议通讯的时候,比如Telnet,会有一个字节字节的发送的情景,每次发送一个字节的有用数据,就会产生41个字节长的分组,20个字节的IP Header 和 20个字节的TCP Header,这就导致了1个字节的有用信息要浪费掉40个字节的头部信息,这是一笔巨大的字节开销,而且这种Small packet在广域网上会增加拥塞的出现(例如在上面过河的场景中,河面上有过多的船只,肯定会造成拥塞)。这种现象还有个奇怪的名字,叫糊涂窗口综合症(Silly Windw Syndrome)。
Nagle算法是为了解决TCP数据发送端“糊涂窗口综合症”而产生的。他的思想也是,在没有收到已发送分组数据的回复ACK之前,不会发送其他分组。他要求TCP连接上最多只能有一个未被确认的小分组,在该分组的确认到达之前不能发送其他的小分组(对应过河的案例中,要求整个河面只有一条船)。相反,TCP收集这些少量的小分组,并在确认到来时以一个分组的方式发出去。
- 【累积确认】有时候,发送方发送速度非常快,接收方一下下接收到了好几个 tcp 段,可以通过累积确认的方式,一次确认好几个 tcp
段,这样减少报文段的传输。 - 【捎带确认】有时候,双方互相发送数据,当接收到对方的 tcp 段后,先不着急确认,而是等待一会儿,连同数据和 ack一起发送过去,这种情况叫捎带确认。如果等了一会儿(到时间了),接收方还没有数据要发送,那就直接回复一个纯 ack 过去,这样的 ack称为延时的 ack(Delayed ACK)。
第20章 TCP的成块数据流
TCP的坚持定时器
在TCP数据发送过程中,如果一个确认丢失了,则双方就有可能因为等待对方而使连接终止。为防止这种死锁情况的发生,发送方使一个坚持定时器来周期性地向接收方查询,以便发现窗口是否已增大。这些从发送方发出的报文称为窗口探查。窗口探查包含一个字节的数据(序号为9217)。TCP总是允许在关闭连接前发送一个字节的数据。坚持状态与超时重传的不同点是TCP从不放弃发送窗口探查,每隔60s发送一次,这个过程将持续到窗口被打开或者连接被终止。
TCP的保活定时器
参考博客地址:https://www.cnblogs.com/zhoudayang/p/5281829.html
一个服务器希望知道客户主机是否崩溃并关机或者重新启动。保活定时器就提供这种能力。如果一个给定的连接在2小时内没有任何动作,那么服务器就向客户发送一个探查报文段。客户主机必须处于以下4个状态之一:
- (1)客户主机依然正常运行,并从服务器可达。客户的TCP响应正常,而服务器也知道对方的正常工作的,服务器在2小时内将保活定时器复位。
- (2)客户主机已经崩溃,并且关闭或者正在重新启动。在任何一种情况下,客户的TCP都没有响应,服务器将不能收到对探查的响应,并在75秒后超时,总共发送10个探查,每个间隔75秒。如果服务器没有收到一个响应,它就认为客户主机已经关闭并终止连接。
- (3)客户主机崩溃并已经重新启动。这是服务器将收到一个对其保活探查的响应,但这个响应是一个RST复位,使得服务器终止这个连接。
- (4)客户主机正常运行,但是从服务器不可达。这与状态2相同,因为TCP不能够区分状态4与2之间的区别,它所能发现的就是没有收到探查的响应。
服务器不用关注客户主机被关闭或者重新启动的情况。当客户机被关闭之后,所有的应用进程也被终止,这会使客户的TCP在连接上发出一个FIN。接收到FIN会使服务器的TCP向服务器进程报告文件结束,从而服务器检测到了这种情况。