TCP协议详解

系列文章目录

第一章 : TCP/IP协议详解
第二章: IP协议
第三章: TCP协议
第四章:面试准备


文章目录

  • 系列文章目录
  • 前言
  • 第三章、TCP协议详解
    • 1 基本介绍
    • 2 头部介绍
    • 3 TCP的连接与断开
      • 3.1TCP的三次握手与四次回收
      • 3.2 TCP的状态转移
        • 3.2.1 TIME_WAIT状态
      • 3.3 TCP的半关闭状态
    • 4 应答机制与数据重发
    • 5 TCP滑动窗口
    • 6 TCP拥塞控制
    • 7 TCP的复位报文段
  • 第四章、UDP协议
  • 附录:面试问题


前言

IP/TCP学习系列目前总共包括4篇,本学习专栏都是自己学习的笔记与总结,前部分来源于游双编著的《Linux高性能服务器编程》,有兴趣的朋友可去学习原文,后面就是各个地方的整理与想法。本人也是在游戏后端中不断摸索前进,不足之处还希望指正!


第三章、TCP协议详解

1 基本介绍

TCP 是面向字节的顺序,流式协议,这意味着包内的每个字节被分配一个顺序编号。
使用TCP协议通讯的双方必须先建立连接,然后才能开始数据的读写。双方都必须为该连接分配必要的内核资源,以管理连接的状态和连接上的数据。TCP是全双工的,即双方的数据读写可以通过同一个连接进行,完成数据交换后,通信双方都必须断开连接以释放资源。
TCP协议的连接是一对一的,所有基于广播和多播的应用程序不能使用TCP,而无连接的UDP非常适合这种情况。

关于具体的使用TCP发送接收操作与缓冲区之间的关系:
当发送端应用程序连续执行多次写操作时,TCP模块先将数据都放入TCP的发送缓冲区中,当TCP模块真正开始发送数据时,发送缓冲区中的等待发送的数据可能被封装成一个或者多个TCP报文段发出。当接收端收到一个或多个TCP报文后,TCP模块先将他们携带的数据按照序号放入接收缓冲区中,并通知应用程序读取,可以一次读取,也可以分次读取,读取的方式取决于用户定义的应用程序读缓冲区的大小。
TCP协议详解_第1张图片
TCP是可靠的,TCP采用发送应答机制,即发送端发送的每一个TCP报文段必须得到接收方的应答,才认为TCP报文传输成功,再结合TCP采用超时重传机制,即发送端发送一个TCP报文后启动一个定时器,如果在定时时间内未收到应答,将会重新发送报文,最后因为TCP报文段最终是以IP数据报发送的,而IP数据报到达接收端可能出现乱序,重复等情况,所有TCP协议还会对接收到的TCP报文段进行重排,整理,再交付给应用层。

2 头部介绍

TCP协议详解_第2张图片
字段说明:
源端口: --》应用进程端口号

目的端口: --》接收进程端口号

顺序号数: --》一次TCP通讯(从TCP连接到断开)过程中某一个传输方向上的字节流的每个字节的编号,(双方都需要维护一个自己的顺序编号)。除设置 SYN 位指出包的开始字节编号外,如果设置了这个位,顺序编号是最初的随机顺序号数(ISN),第一个数据字节是 ISN+1(握手后)。在TCP中数据不是按包排序,是按字节排序,每个包Seq Bumber代表的是发送主机的起始序号。发送的第一个包的初始序号是随机的,在创建连接的三次握手中交换。

确认编号数: --》目的地站点向源站点发送的编号。对以前所接收的包(或许多包)表明确认。该序号指出目的地站点希望接收下一个顺序(字节)编号。一旦建立了连接就始终设置这个字段。
例如:A向B发送一个数据包,其中Seq Number=1000,大小位1000字节,则B收到该包后,返回的ACk number=2001(表明希望接收的下一个编号)。

4位头部字段: --》标识该TCP头部有多少个32bit,因为4位最大能标识15,故tcp头部最长是60字节

6位标志位(控制位): --》

URG 标志 表示紧急指针是否有效
ACK标志 表示确认号是否有效,称携带ACK标志的TCP报文段称为确认报文段
PSH标志 提示接收端应用程序应该立即从TCP缓冲区中读取数据,为后续接收腾出空间
RST标志 要求对方重新建立连接,携带该标志为复位报文段
SYN标志 表示对方请求建立一个连接,携带SYN标志称为同步报文段
FIN标志 通知对方本端要关闭连接了,携带FIN标志称为结束报文段

窗口: --》TCP流量控制的一种的一种手段,这里的窗口是指接收窗口,即告诉对方自己的接收缓冲区还能容纳多少字节的数据,这样可以控制对方发送数据的速度(也是拥塞控制的一种手段)。

保留位: -》为未来使用而保留。必须设置为 0。

CRC 校验和: -》一个差错检验数,用于确定被接收的数据报文在传输期间是否被讹误。包括 TCP头部和 所有数据

紧急指示器:-》 是一个正的偏移量,它指出了紧接紧急数据的字节的顺序编号。

选项: -》长度变量,它考虑到 TCP 使用的各种选项:
选项最长40字节,因为TCP头部最长60字节。
(1)选项表的结束 (2)无操作 (3)最大分段长度

TCP提供的主要服务有:
(1)建立、维持和终结两个进程之间的连接。
(2)可靠的包传递(经过确认过程)。
(3)编序包(可靠的数据传送)。
(4)控制差错的机制。
(5)通过使用端口,允许在个别的源和目的地主机内部实现和不同进程多重连接的能力。
(6)使用全双工操作的数据交换。

3 TCP的连接与断开

3.1TCP的三次握手与四次回收

<注意整个过程的状态>
TCP协议详解_第3张图片
(第一次握手) 由client主动发出SYN请求, 此时client处于SYN_SENT状态
当server收到之后会由LISTEN转变为SYN_REVD状态,
(第二次握手) 并回复client, client收到应答后处于ESTABLISHED状态, 这个状态就表示client已经准备好通信了
(第三次握手) client收到二次握手应答后回复server, server收到应答之后也处于ESTABLISHED, 表示握手成功, 可以通信了

(。。。。可以开始进行数据传输了。。。)数据传输的状态不会改变,都是ESTABLISHED
TCP协议详解_第4张图片
(第一次挥手) client主动发送FIN报文段,请求关闭, 此时client处于FIN_WAIT_1状态(短暂)
(第二次挥手) server收到之后处于CLOSE_WAIT状态(半关闭状态), 并做出应答client收到之后处于FIN_WAIT_2状态, 等待server发送关闭请求.
(第三次挥手) server会紧接着发送FIN断开请求, 并处于LAST_ACK,
(第四次挥手) client收到之后并应答服务器, 此时处于TIME_WAIT状态, 这是主动断开的一端的最后一个状态, 待一定的时间(2MSL-1min), 等待之后会变成CLOSED状态

3.2 TCP的状态转移

TCP连接的任意一端在任一时刻都处于某种状态下,状态转换如图所示:
TCP协议详解_第5张图片
CLOSED: 起始点,在超时或者连接关闭时候进入此状态,这并不是一个真正的状态,而是这个状态图的假想起点和终点。
LISTEN: 服务器端等待连接的状态。服务器经过 socket,bind,listen 函数之后进入此状态,开始监听客户端发过来的连接请求。此称为应用程序被动打开(等到客户端连接请求)。
SYN_SENT: 第一次握手发生阶段,客户端发起连接。客户端调用 connect,发送 SYN 给服务器端,然后进入 SYN_SENT 状态,等待服务器端确认(三次握手中的第二个报文)。如果服务器端不能连接,则直接进入CLOSED状态。
SYN_RCVD: 第二次握手发生阶段,跟 3 对应,这里是服务器端接收到了客户端的 SYN,此时服务器由 LISTEN 进入 SYN_RCVD状态,同时服务器端回应一个 ACK,然后再发送一个 SYN 即 SYN+ACK 给客户端。状态图中还描绘了这样一种情况,当客户端在发送 SYN 的同时也收到服务器端的 SYN请求,即两个同时发起连接请求,那么客户端就会从 SYN_SENT 转换到 SYN_REVD 状态。
ESTABLISHED: 第三次握手发生阶段,客户端接收到服务器端的 ACK 包(ACK,SYN)之后,也会发送一个 ACK 确认包,客户端ESTABLISHED 状态,表明客户端这边已经准备好,但TCP 需要两端都准备好才可以进行数据传输。服务器端收到客户端的 ACK 之后会从 SYN_RCVD 状态转移到 ESTABLISHED 状态,表明服务器端也准备好进行数据传输了。这样客户端和服务器端都是 ESTABLISHED 状态,就可以进行后面的数据传输了。所以 ESTABLISHED 也可以说是一个数据传送状态。

下面看看TCP四次挥手过程的状态变迁。
FIN_WAIT_1: 第一次挥手。主动关闭的一方(执行主动关闭的一方既可以是客户端,也可以是服务器端,这里以客户端执行主动关闭为例),终止连接时,发送 FIN 给对方,然后等待对方返回 ACK 。调用 close() 第一次挥手就进入此状态。
CLOSE_WAIT: 接收到FIN 之后,被动关闭的一方进入此状态。具体动作是接收到 FIN,同时发送 ACK。之所以叫 CLOSE_WAIT 可以理解为被动关闭的一方此时正在等待上层应用程序发出关闭连接指令。TCP关闭是全双工过程,这里客户端执行了主动关闭,被动方服务器端接收到FIN 后也需要调用 close 关闭,这个CLOSE_WAIT 就是处于这个状态,等待发送 FIN,发送了FIN 则进入 LAST_ACK 状态。
FIN_WAIT_2: 主动端(这里是客户端)先执行主动关闭发送FIN,然后接收到被动方返回的 ACK 后进入此状态。
LAST_ACK: 被动方(服务器端)发起关闭请求,由状态2 进入此状态,具体动作是发送 FIN给对方,同时在接收到ACK 时进入CLOSED状态。
CLOSING:两边同时发起关闭请求时(即主动方发送FIN,等待被动方返回ACK,同时被动方也发送了FIN,主动方接收到了FIN之后,发送ACK给被动方),主动方会由FIN_WAIT_1 进入此状态,等待被动方返回ACK。
**TIME_WAIT:**从状态变迁图会看到,四次挥手操作最后都会经过这样一个状态然后进入CLOSED状态。

处于FIN_WAIT_2状态的客户端需要等待服务器发送结束报文段,才能转移到TIME_WAIT状态,否则它将一直处于这个状态。如果不是为了在半关闭状态下继续接收数据,连接长时间地停留在FIN_WAIT_2状态并无益处。连接停留在FIN_WAIT_2状态的情况。连接停留在FIN_WAIT_2状态的情况可能发生在:客户端执行半关闭后,未等服务器关闭连接就强行退出。此时客户端连接由内核来接管,可称为孤儿进程。

3.2.1 TIME_WAIT状态

客户端连接在收到服务器的结束报文段之后,并没有直接进入CLOSED状态,而是转移到TIME_WAIT状态。这个状态,客户端连接要等待一段长为2MSL(报文段最大生存时间)的时间,才能完全关闭。MSL是TCP报文段在网络中的最大生存时间。
TIME_WAIT状态存在的原因有两点:
可靠地终止TCP连接—》如果服务器发送FIN报文段,客户端不能够确认,那么服务器将重发结束报文段,因此客户端需要停留在该状态以处理重复收到的结束报文段(即向服务器发送确认报文段)。

保证让迟来的TCP报文段有足够的时间被识别并丢弃–》在linux系统上,一个TCP端口不能被同时打开>1次,当一个TCP连接处于TIME_WAIT状态时,我们无法立即使用该连接占用的端口来建立一个新连接。如果不存在这个状态,应用程序能够立即建立一个相似的连接(指具有相同的端口 和 IP地址的连接),新的化身可能接收原来的连接的信息,所以这是第二个原因。

关于为什么是2MSL,TCP报文段的最大生存时间是MSL(即发送端发送报文时刻,定时器开始,到收到ACK报文,定时器的时间),坚持2MSL的TIME_WAIT状态能够确保网络上两个传输方向上尚未被接收到的,迟到的TCP报文都消失(被路由器丢弃),因此一个连接的新的化身在2MSL时间之后建立是安全的,保证绝对不会接收到原来连接的应用数据。

3.3 TCP的半关闭状态

TCP连接是全双工的,所有它允许两个方向的数据传输被独立关闭,换言之,通讯的一端可以发送结束报文段给对方,告诉它本端已经完成了数据的发送,但允许继续接收来自对方的数据,直到对方也发送结束报文段以关闭连接。TCP连接的这种状态称为半关闭状态。
TCP协议详解_第6张图片 注意,服务器和客户端应用程序判断对方是否已经关闭连接的方法是:read系统调用返回0(收到结束报文),当然Linux还提供其他检测连接是否被对方关闭的方法。

4 应答机制与数据重发

TCP协议详解_第7张图片
说明:TCP的超时时间机制与ACK机制保证了,数据丢失和未收到ACK情况下的数据重发。

5 TCP滑动窗口

TCP的滑动窗口中,发送窗口和接收窗口是互相配合的,(滑动窗口包括接收窗口和发送窗口)
TCP是全双工通信,因此每一方的滑动窗口都包括了接收窗口+发送窗口,接收窗口负责处理自己接收到的数据,发送窗口负责处理自己要发送出去的数据。
滑动窗口的本质其实就是维护几个变量,通过这些变量将TCP处理的数据分为几类,同时在发送出一个报文、接收一个报文对这些变量做一定的处理维护。
发送报文,等待对方确认,收到确认后继续发下一报文,效率非常低。而有了滑动窗口,通信双方就不用发送一个报文后,收到此报文的确认后再发送下一个报文,而是可以连续发送多个报文,只要别超过窗口大小限制;
还有就是:TCP开销比UDP大,一旦网络拥塞或报文丢失又会造成报文重发,而这些重发又加重了拥塞,所以
TCP里要严格控制发送速率防止网络拥塞,滑动窗口根据接收方的Windows大小很好的限制了发送方的发送速
率。
TCP协议详解_第8张图片
发送窗口如上图 :
(1)N是发送窗口的起始字节,也就是说:字节序号 < N的字节都已经发送出去且已经收到ack,确认无误了;
(2)nextSeq就是下一次发送报文的首部Seq字段,表示字节序号在 [N,nextSeq)区间的都已经使用过,发送出去了,但是还未收到ack确认;
(3) N+size就是窗口的最后一个可用字节序号,size是发送窗口的大小,就是每次接收到的报文中的Win字段的值,Win字段其实就是对方接收窗口的大小。(表示能发多少)

发送串口值的维护:
(1)每接收到一个一个报文要做如下事情:检查接收报文的ack,将N 置为 ack,即往前移到ack这个值;读取报文中的Win字段值,即对方的最新接收窗口大小,从而更新N+size的值。
(2)每发送一个报文,就更改nextSeq的值,发送了多少个字节就把nextSeq往前移多少,但是不要超出N+size。

TCP协议详解_第9张图片
接收窗口如上图 :
字节序号都是接收到的字节
(1)J1表示:字节序号 < J1的字节已经接收到了,即已经发出ack确认了, 程序读取接收缓冲区k个字节,J1会增加k。
(2)J2表示:[J1,J2)区间的字节已经完整、有序的接收到了,但还在缓冲区,没有发出ack进行确认,随时可以供程序读取。
(3)J2,J3表示对面还未发送。
接收窗口的维护:
(1)发送一个报文时:将J1的值填入报文首部的ack字段;将 (J3-J2) 的差值填入首部Win字段,告诉对方我还有多 大空间可以接收。
(2)接收到一个报文时,如果报文顺序没出错,则将移动J2,接收到多少字节就移动多少。如果报文按序到达,下一个收到的报文的Seq值就应该等于J2,如果不相等说明中间有报文丢失了,就不移动J2,从 而接下来发送的报文ack一直是同一个:J2,也就是重复确认,相应的又有快重传。

总结:
(1)滑动窗口允许发送方连续发送多个报文
(2)根据对方接收窗口大小限制发送方的发送速率,防止拥塞

6 TCP拥塞控制

TCP模块还有一个重要的任务,就是提高网络利用率,降低丢包率,保证网络资源对每条数据流的公平性,这就是拥塞控制。
TCP拥塞控制的标志文档,介绍了拥塞控制的四部分:慢启动,拥塞避免,快速重传,快速恢复
拥塞控制算法在Linux上有多少实现,如reno算法,vegas算法和cubic算法等,他们部分或者全部实现了上述四部分。

拥塞控制对最终受控变量是发送方向网络一次连续写入(收到其中第一个数据的确认之前)的数据量,称发送窗口。发送端最终以TCP报文发送数据,所以发送窗口限定了能连续法按时的TCP报文段数量,这些TCP报文段的最大长度(仅数据)称为SMSS(发生着最大段数),其值一般等于MSS。

发送端需要合理控制发送窗口的大小,小了出现网络延迟,大了出现网络拥塞。接收方可以通过接收窗口来控制发送端的发送窗口,这样显然不够,所以发送端引入了一个称为拥塞窗口的状态变量,实际的发送窗口的值是MIN(接收窗口,拥塞窗口)。
CWND(拥塞窗口) SWND(发送窗口) RWND(接收窗口)
TCP协议详解_第10张图片
–》 慢启动,拥塞避免
在这里插入图片描述
TCP协议详解_第11张图片
TCP协议详解_第12张图片
–》快速重传,快速恢复

TCP协议详解_第13张图片
TCP协议详解_第14张图片

7 TCP的复位报文段

在某些情况下,TCP连接的一端会向另一端发送携带RTS标志的报文段,即复位报文段,以通知对方关闭连接或重新建立连接。
–》访问不存在的端口:
当客户端程序访问一个不存在的端口时,目标主机将给他发送一个复位报文段。收到复位报文段的额一端应该立即关闭连接或者重新连接。实际上,当客户端向服务器的某个端口发起连接,而该端口任被处于TIME_WAIT的连接占用,客户端也会收到复位报文段。
–》异常终止连接:
TCP提供一个异常终止连接的方法,即发送一个复位报文段。
–》处理半打开连接:
半打开连接:服务器(客户端)关闭或者异常终止,而对方没有收到结束报文段,而客户端(服务器)还维持在原来的连接,即使服务器(客户端重启),也已经没有该该连接的任何信息,这种状态就是半打开状态。

第四章、UDP协议

1 相关说明:它是无连接的,不可靠的传输服务。当接收数据时它不向发送方提供确认信息,它不提供输入包的
顺序,如果出现丢失包或重份包的情况,也不会向发送方发出差错报文。

2 头说明:
TCP协议详解_第15张图片

附录:面试问题

1 说说 TCP 2次握手行不行?为什么要3次
为了实现可靠数据传输, TCP 协议的通信双方, 都必须维护一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤.
如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认
《三次握手是为了双方都能确认各种维护的序列号SYN》

2 TCP 和 UDP 的区别
TCP协议是有连接的,有连接的意思是开始传输实际数据之前TCP的客户端和服务器端必须通过三次握手建立连接,会话结束之后也要结束连接。而UDP是无连接的.
TCP协议保证数据按序发送,按序到达,提供超时重传来保证可靠性,但是UDP不保证按序到达,甚至不保证到达,只是努力交付,即便是按序发送的序列,也不保证按序送到。
TCP协议所需资源多,TCP首部需20个字节(不算可选项),UDP首部字段只需8个字节。
TCP有流量控制和拥塞控制《滑动窗口机制》,UDP没有,网络拥堵不会影响发送端的发送速率
TCP是一对一的连接,而UDP则可以支持一对一,多对多,一对多的通信。
TCP面向的是字节流的服务,UDP面向的是报文的服务。

3 简述 TCP 慢启动
慢启动(Slow Start),是传输控制协议(TCP)使用的一种阻塞控制机制。慢启动也叫做指数增长期。慢启动是指每次TCP接收窗口收到确认时都会增长。增加的大小就是已确认段的数目。这种情况一直保持到要么没有收到一些段,要么窗口大小到达预先定义的阈值。如果发生丢失事件,TCP就认为这是网络阻塞,就会采取措施减轻网络拥挤。一旦发生丢失事件或者到达阈值,TCP就会进入线性增长阶段。这时,每经过一个RTT窗口增长一个段。
重传机制需要设置一个重传超时值(RTO,Retransmission TimeOut),RTO设长了,重发太慢;设短了,可能导致包没有丢,就重发了,可能导致雪崩效应(重发多,失败多,失败多,导致更多的重发)。
那么该值怎么设置?
由于一开始无法确定设置某个值,所以需要程序自动适应,动态地去设置
RTT,Round Trip Time,设置的参考值为数据报来回所需要的时间

4 说说 TCP 如何保证有序
主机每次发送数据时,TCP就给每个数据包分配一个序列号并且在一个特定的时间内等待接收主机对分配的这个序列号进行确认,如果发送主机在一个特定时间内没有收到接收主机的确认,则发送主机会重传此数据包。接收主机利用序列号对接收的数据进行确认,以便检测对方发送的数据是否有丢失或者乱序等,接收主机一旦收到已经顺序化的数据,它就将这些数据按正确的顺序重组成数据流并传递到高层进行处理。
具体步骤如下:
(1)为了保证数据包的可靠传递,发送方必须把已发送的数据包保留在缓冲区;
(2)并为每个已发送的数据包启动一个超时定时器;
(3)如在定时器超时之前收到了对方发来的应答信息(可能是对本包的应答,也可以是对本包后续包的应答),则释放该数据包占用的缓冲区;
(4)否则,重传该数据包,直到收到应答或重传次数超过规定的最大次数为止。
(5)接收方收到数据包后,先进行CRC校验,如果正确则把数据交给上层协议,然后给发送方发送一个累计应答 包,表明该数据已收到,如果接收方正好也有数据要发给发送方,应答包也可方在数据包中捎带过去。

5 说说 TCP 常见的拥塞控制算法有哪些
TCP Tahoe/Reno
最初的实现,包括慢启动、拥塞避免两个部分。基于重传超(retransmission timeout/RTO)和重复确认为条件判断是否发生了丢包。两者的区别在于:Tahoe算法下如果收到三次重复确认,就进入快重传立即重发丢失的数据包,同时将慢启动阈值设置为当前拥塞窗口的一半,将拥塞窗口设置为1MSS,进入慢启动状态;而Reno算法如果收到三次重复确认,就进入快重传,但不进入慢启动状态,而是直接将拥塞窗口减半,进入拥塞控制阶段,这称为"快恢复"。而Tahoe和Reno算法在出现RTO时的措施一致,都是将拥塞窗口降为1个MSS,然后进入慢启动阶段。

TCP BBR(瓶颈带宽和往返传播时间)
BBR是由谷歌设计,于2016年发布的拥塞算法。以往大部分拥塞算法是基于丢包来作为降低传输速率的信号,而BBR则基于模型主动探测。该算法使用网络最近出站数据分组当时的最大带宽和往返时间来建立网络的显式模型。数据包传输的每个累积或选择性确认用于生成记录在数据包传输过程和确认返回期间的时间内所传送数据量的采样率。该算法认为随着网络接口控制器逐渐进入千兆速度时,分组丢失不应该被认为是识别拥塞的主要决定因素,所以基于模型的拥塞控制算法能有更高的吞吐量和更低的延迟,可以用BBR来替代其他流行的拥塞算法,例如CUBIC。

6 简述 TCP 超时重传
超时重传是指发送出去的数据包到接收到确认包之间的时间,如果超过了这个时间会被认为是丢包了,需要重传。
TCP可靠性中最重要的一个机制是处理数据超时和重传。TCP协议要求在发送端每发送一个报文段,就启动一个定时器并等待确认信息;接收端成功接收新数据后返回确认信息。若在定时器超时前数据未能被确认,TCP就认为报文段中的数据已丢失或损坏。
那么我们该如何确认这个时间值呢?
我们知道,一来一回的时间总是差不多的,都会有一个类似于平均值的概念。比如发送一个包到接收端收到这个包一共是0.5s,然后接收端回发一个确认包给发送端也要0.5s,这样的两个时间就是RTT(往返时间)。然后可能由于网络原因的问题,时间会有偏差,称为抖动(方差)。
从上面的介绍来看,超时重传的时间大概是比往返时间+抖动值还要稍大的时间。
TCP协议详解_第16张图片
但是在重发的过程中,假如一个包经过多次的重发也没有收到对端的确认包,那么就会认为接收端异常,强制关闭连接。并且通知应用通信异常强行终止。

7 说说 TCP 可靠性保证
TCP主要提供了检验和、序列号/确认应答、超时重传、最大消息长度、滑动窗口控制等方法实现了可靠性传输。
检验和
检验和的方式,接收端可以检测出来数据是否有差错和异常,假如有差错就会直接丢弃TCP段,重新发送。TCP在计算检验和时,会在TCP首部加上一个12字节的伪首部。检验和总共计算3部分:TCP首部、TCP数据、TCP伪首部
TCP协议详解_第17张图片

8 最大消息长度
在建立TCP连接的时候,双方约定一个最大的长度(MSS)作为发送的单位,重传的时候也是以这个单位来进行重传。理想的情况下是该长度的数据刚好不被IP网络层分块。
TCP协议详解_第18张图片
9 拥塞控制
窗口控制解决了 两台主机之间因传送速率而可能引起的丢包问题,在一方面保证了TCP数据传送的可靠性。然而如果网络非常拥堵,此时再发送数据就会加重网络负担,那么发送的数据段很可能超过了最大生存时间也没有到达接收方,就会产生丢包问题。为此TCP引入慢启动机制,先发出少量数据,就像探路一样,先摸清当前的网络拥堵状态后,再决定按照多大的速度传送数据。
发送开始时定义拥塞窗口大小为1;每次收到一个ACK应答,拥塞窗口加1;而在每次发送数据时,发送窗口取拥塞窗口与接送段接收窗口最小者。
慢启动:在启动初期以指数增长方式增长;设置一个慢启动的阈值,当以指数增长达到阈值时就停止指数增长,按照线性增长方式增加至拥塞窗口;线性增长达到网络拥塞时立即把拥塞窗口置回1,进行新一轮的"慢启动",同时新一轮的阈值变为原来的一半。
TCP协议详解_第19张图片
10 说说如果三次握手时候每次握手信息对方没收到会怎么样,分情况介绍
如果第一次握手消息丢失,那么请求方不会得到ack消息,超时后进行重传
如果第二次握手消息丢失,那么请求方不会得到ack消息,超时后进行重传
如果第三次握手消息丢失,那么Server 端该TCP连接的状态为SYN_RECV,并且会根据 TCP的超时重传机制,会等待3秒、6秒、12秒后重新发送SYN+ACK包,以便Client重新发送ACK包。而Server重发SYN+ACK包的次数,可以设置/proc/sys/net/ipv4/tcp_synack_retries修改,默认值为5.如果重发指定次数之后,仍然未收到客户端 的ACK应答,那么一段时间后,Server自动关闭这个连接。

client 一般是通过 connect() 函数来连接服务器的,而connect()是在 TCP的三次握手的第二次握手完成后就成功返回值。也就是说客户端 在接收到 SYN+ACK包,它的TCP连接状态就为已建立 (已连接),表示该连接已经建立。那么如果 第三次握手中的ACK包丢失的情况下,Client 向 server端发送数据,Server端将以 RST包响应,方能感知到Server的错误。

11 简述 TCP 的 TIME_WAIT,为什么需要有这个状态
TIME_WAIT状态也称为2MSL等待状态。每个具体TCP实现必须选择一个报文段最大生存时间MSL(Maximum Segment Lifetime),它是任何报文段被丢弃前在网络内的最长时间。这个时间是有限的,因为TCP报文段以IP数据报在网络内传输,而IP数据报则有限制其生存时间的TTL字段。
对一个具体实现所给定的MSL值,处理的原则是:当TCP执行一个主动关闭,并发回最后一个ACK,该连接必须在TIME_WAIT状态停留的时间为2倍的MSL。这样可让TCP再次发送最后的ACK以防这个ACK丢失(另一端超时并重发最后的FIN)。
理论上,四个报文都发送完毕,就可以直接进入CLOSE状态了,但是可能网络是不可靠的,有可能最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。
MSL是Maximum Segment Lifetime的英文缩写,可译为“最长报文段寿命”,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。
为了保证客户端发送的最后一个ACK报文段能够到达服务器。因为这个ACK有可能丢失,从而导致处在LAST-ACK状态的服务器收不到对FIN-ACK的确认报文。服务器会超时重传这个FIN-ACK,接着客户端再重传一次确认,重新启动时间等待计时器。最后客户端和服务器都能正常的关闭。假设客户端不等待2MSL,而是在发送完ACK之后直接释放关闭,一但这个ACK丢失的话,服务器就无法正常的进入关闭连接状态。
为了保证客户端发送的最后一个ACK报文段能够到达服务器。因为这个ACK有可能丢失,从而导致处在LAST-ACK状态的服务器收不到对FIN-ACK的确认报文。服务器会超时重传这个FIN-ACK,接着客户端再重传一次确认,重新启动时间等待计时器。最后客户端和服务器都能正常的关闭。假设客户端不等待2MSL,而是在发送完ACK之后直接释放关闭,一但这个ACK丢失的话,服务器就无法正常的进入关闭连接状态。

12 说说什么是 TCP 粘包和拆包?
TCP是个“流”协议,所谓流(理解流,就能理解粘包和拆包了),就是没有界限的一串数据。大家可以想想河里的流水,是连成一片的,其间并没有分界线。TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送(拆包),也有可能把多个小的包封装成一个大的数据包发送(粘包),这就是所谓的TCP粘包和拆包问题。

13 说说从系统层面上,UDP 如何保证尽量可靠?
UDP仅提供了最基本的数据传输功能,至于传输时连接的建立和断开、传输可靠性的保证这些UDP统统不关心,而是把这些问题抛给了UDP上层的应用层程序去处理,自己仅提供传输层协议的最基本功能。
最简单的方式是在应用层模仿传输层TCP的可靠性传输。下面不考虑拥塞处理,可靠UDP的简单设计。
添加seq/ack机制,确保数据发送到对端
添加发送和接收缓冲区,主要是用户超时重传。
添加超时重传机制。 (对你RTP协议)

14 说一说 TCP 的 keepalive,以及和 HTTP 的 keepalive 的区别?
HTTP Keep-Alive
在http早期,每个http请求都要求打开一个tpc socket连接,并且使用一次之后就断开这个tcp连接。使用keep-alive可以改善这种状态,即在一次TCP连接中可以持续发送多份数据而不会断开连接。通过使用keep-alive机制,可以减少tcp连接建立次数,也意味着可以减少TIME_WAIT状态连接,以此提高性能和提高http服务器的吞吐率(更少的tcp连接意味着更少的系统内核调用,socket的accept()和close()调用)。但是,keep-alive并不是免费的午餐,长时间的tcp连接容易导致系统资源无效占用。配置不当的keep-alive,有时比重复利用连接带来的损失还更大。所以,正确地设置keep-alive timeout time非常重要。
TCP KEEPALIVE
链接建立之后,如果应用程序或者上层协议一直不发送数据,或者隔很长时间才发送一次数据,当链接很久没有数据报文传输时如何去确定对方还在线,到底是掉线了还是确实没有数据传输,链接还需不需要保持,这种情况在TCP协议设计中是需要考虑到的。TCP协议通过一种巧妙的方式去解决这个问题,当超过一段时间之后,TCP自动发送一个数据为空的报文给对方,如果对方回应了这个报文,说明对方还在线,链接可以继续保持,如果对方没有报文返回,并且重试了多次之后则认为链接丢失,没有必要保持链接。
TCP的keepalive机制和HTTP的keep-alive机制是说的完全不同的两个东西,tcp的keepalive是在ESTABLISH状态的时候,双方如何检测连接的可用行。而http的keep-alive说的是如何避免进行重复的TCP三次握手和四次挥手的环节。

15 服务器怎么判断客户端断开了连接
检测连接是否丢失的方法大致有两种:keepalive和heart-beat
(tcp内部机制)采用keepalive,它会先要求此连接一定时间没有活动(一般是几个小时),然后发出数据段,经过多次尝试后(每次尝试之间也有时间间隔),如果仍没有响应,则判断连接中断。可想而知,整个周期需要很长的时间。
(应用层实现)一个简单的heart-beat实现一般测试连接是否中断采用的时间间隔都比较短,可以很快的决定连接是否中断。并且,由于是在应用层实现,因为可以自行决定当判断连接中断后应该采取的行为,而keepalive在判断连接失败后只会将连接丢弃。

16 说说 TCP 如何加速一个大文件的传输
建连优化:TCP 在建立连接时,如果丢包,会进入重试,重试时间是 1s、2s、4s、8s 的指数递增间隔,缩短定时器可以让 TCP 在丢包环境建连时间更快,非常适用于高并发短连接的业务场景。
平滑发包:在 RTT 内均匀发包,规避微分时间内的流量突发,尽量避免瞬间拥塞
丢包预判:有些网络的丢包是有规律性的,例如每隔一段时间出现一次丢包,例如每次丢包都连续丢几个等,如果程序能自动发现这个规律(有些不明显),就可以针对性提前多发数据,减少重传时间、提高有效发包率。
RTO 探测:若始终收不到 ACK 报文,则需要触发 RTO 定时器。RTO 定时器一般都时间非常长,会浪费很多等待时间,而且一旦 RTO,CWND 就会骤降(标准 TCP),因此利用 Probe 提前与 RTO 去试探,可以规避由于 ACK 报文丢失而导致的速度下降问题。
带宽评估:通过单位时间内收到的 ACK 或 SACK 信息可以得知客户端有效接收速率,通过这个速率可以更合理的控制发包速度。
带宽争抢:有些场景(例如合租)是大家互相挤占带宽的,假如你和室友各 1Mbps 的速度看电影,会把 2Mbps 出口占满,而如果一共有 3 个人看,则每人只能分到 1/3。若此时你的流量流量达到 2Mbps,而他俩还都是 1Mbps,则你至少仍可以分到 2/(2+1+1) * 2Mbps = 1Mbps 的 50% 的带宽,甚至更多,代价就是服务器侧的出口流量加大,增加成本。(TCP 优化的本质就是用带宽换用户体验感)

17 说说端到端,点到点的区别
端到端通信是针对传输层来说的,传输层为网络中的主机提供端到端的通信。因为无论tcp还是udp协议,都要负责把上层交付的数据从发送端传输到接收端,不论其中间跨越多少节点。只不过tcp比较可靠而udp不可靠而已。所以称之为端到端,也就是从发送端到接收端。
它是一个网络连接,指的是在数据传输之前,在发送端与接收端之间(忽略中间有多少设备)为数据的传输建立一条链路,链路建立以后,发送端就可以发送数据,知道数据发送完毕,接收端确认接收成功。也就是说在数据传输之前,先为数据的传输开辟一条通道,然后在进行传输。从发送端发出数据到接收端接收完毕,结束。
端到端通信建立在点到点通信的基础之上,它是由一段段的点到点通信信道构成的,是比点到点通信更高一级的通信方式,完成应用程序(进程)之间的通信。
端到端的优点:
链路建立之后,发送端知道接收端一定能收到,而且经过中间交换设备时不需要进行存储转发,因此传输延迟小。
端到端传输的缺点:
(1)直到接收端收到数据为止,发送端的设备一直要参与传输。如果整个传输的延迟很长,那么对发送端的设备造成很大的浪费。
(2)如果接收设备关机或故障,那么端到端传输不可能实现。
点到点通信是针对数据链路层或网络层来说的,因为数据链路层只负责直接相连的两个节点之间的通信,一个节点的数据链路层接受ip层数据并封装之后,就把数据帧从链路上发送到与其相邻的下一个节点。点对点是基于MAC地址和或者IP地址,是指一个设备发数据给与该这边直接连接的其他设备,这台设备又在合适的时候将数据传递给与它相连的下一个设备,通过一台一台直接相连的设备把数据传递到接收端。
直接相连的节点对等实体的通信叫点到点通信。它只提供一台机器到另一台机器之间的通信,不会涉及到程序或进程的概念。同时点到点通信并不能保证数据传输的可靠性,也不能说明源主机与目的主机之间是哪两个进程在通信。
由物理层、数据链路层和网络层组成的通信子网为网络环境中的主机提供点到点的服务
点到点的优点:
(1)发送端设备送出数据后,它的任务已经完成,不需要参与整个传输过程,这样不会浪费发送端设备的资源。
(2)即使接收端设备关机或故障,点到点传输也可以采用存储转发技术进行缓冲。
点到点的缺点:
点到点传输的缺点是发送端发出数据后,不知道接收端能否收到或何时能收到数据。
在一个网络系统的不同分层中,可能用到端到端传输,也可能用到点到点传输。如Internet网,IP及以下各层采用点到点传输,4层以上采用端到端传输。

你可能感兴趣的:(IP/TCP学习笔记,tcp/ip,网络,服务器)