传输层
1.TCP首部格式
为了实现可靠传输,TCP采用面向字节流的方式。
- **源端口:**16位,标识报文的返回地址。
- **目的端口:**16位,指明接收方计算机上的应用程序接口。
- **序列号:**32位,在建立连接时由计算机生成的随机数作为其初始值,通过SYN包传给接收端主机,每发送一次数据,就累加一次该数据字节数的大小。用来解决网络包乱序问题。
- **确认号:**32位,下一次期望收到数据的序列号,发送端收到这个确认应答以后可以认为在这个序列号以前的数据都已经被正常接收。用来解决丢包问题。
- **数据偏移/首部长度:**4位,TCP首部可能含有可选项内容,所以TCP报文的长度是不确定的,报头默认有20字节,4位首部长度字段最大为60字节。首部长度也叫做数据偏移,因为首部长度实际上指示了数据区在报文段中的起始偏移量。
- **保留:**6位,为将来定义新的用途保留,现在一般置为0 。
- **校验和:**16位,由发送端填充,接收端对TCP报文段执行CRC算法以检验TCP报文段在传输过程中是否损坏,这个校验不仅包括TCP头部,也包括数据部分。这是TCP实现可靠传输的一个重要保障。
- **窗口:**16位,是TCP流量控制的一个手段。通过窗口告诉对方本端的TCP接收缓冲区还能容纳多少字节的数据,这样对方可以控制发送数据的速度,从而达到流量控制。窗口大小为16bit字段,因而窗口大小最大为65535 。
- **紧急指针:**16位,只有当URG标志置1时,紧急指针才有效。紧急指针是一个正的偏移量,和顺序号字段中的值相加表示紧急数据最后一个字节的序号。使用紧急指针是发送端向另一端发送紧急数据的一种方式。
- **选项和填充:**TCP头部的最后一个选项字段是可变长的可选信息。这部分最多包含40字节,因为TCP头部最长是60字节。最常见的可选字段是最长报文大小MSS,每个连接方通常都在通信的第一个报文段中指明这个选项,它表示本端所能接收的最大报文段的长度。
- **数据部分:**TCP报文段中的数据部分是可选的。在连接建立或终止时,双方交换的报文段仅有TCP首部,如果一方没有数据要发送,也会使用没有任何数据的首部来确认收到数据,在处理超时的许多情况,也会发送不带任何数据的保文段。
控制位:
- **URG:**紧急指针标识,为1时表示紧急指针有效,该报文应该优先传送,为0则忽略紧急指针。
- **ACK:**确认序号标志,为1时表示确认号有效,为0时表示报文中不含确认消息。携带ACK标识的TCP报文被称为确认报文段。
- **RST:**重置连接标志,用于重置由于主机崩溃或其他原因而出现错误的连接,或者用于拒绝非法的报文段和拒绝连接请求。称携带RST标志的TCP报文段为复位报文段。
- **SYN:**表示请求建立一个连接。称携带SYN标志的TCP报文段为同步报文段。
- **FIN:**finish标志,用于释放连接,为1时表示发送方已经没有数据发送了,即关闭本方数据流。称携带FIN标志的TCP报文段为结束报文段。
- **PSH:**push标志,为1表示时带有push的数据,指示接收方在接收到该报文段以后,应优先将这个报文段交给应用程序,而不是在缓冲区排队。
2.TCP三次握手与四次挥手
TCP是一个工作在传输层的可靠数据传输的服务,它能确保接收端的网络包是无损坏的、无间隔、非冗余和按序的。
- 面向连接:一对一
- 可靠的
- 字节流
建立一个TCP连接需要客户端与服务端达成三个共识:
- Socket:由IP地址和端口号组成。
- 序列号:用来解决乱序问题。
- 窗口大小:用来做流量控制。
1、如何唯一确定一个TCP连接?
TCP四元组可以唯一确定一个连接:
- 源地址和目的地址的字段32位在IP头部中,可以通过IP协议发送报文给对方主机。
- 源端口和目的端口的字段16位在TCP头部中,告诉TCP协议应该吧报文发送给那个进程。
最大TCP连接数=客户端的IP数*客户端的端口数
2、TCP和UDP有什么区别呢?分别应用场景?
UDP头部格式:
- 目标和源端口:告诉UDP协议应该把报文发送给那个进程。
- 包长度:该字段保存了UDP首部的长度跟数据的长度之和。
- 校验和:提供可靠的UDP首部和数据而设计,防止在网络传输中受损的UDP包。
区别:
- TCP是面向连接的协议,在发送数据的时候,需要先建立TCP三次握手,而UDP是无连接的协议,可以直接发送数据。
- TCP会通过超时重传、流量控制、拥塞控制保证数据的可靠传输,而UDP并没有这些特性,UDP不考虑数据的可靠性。
- TCP发送数据是以字节流的形式,没有边界。而UDP是一个一个包的发送,是有边界的。
总结,TCP的优势就是在于可以可靠传输,UDP是足够简单,不用建立连接,传输速度快。
TCP和UDP使用时机:
- 如果主要关注数据接收的可靠性和顺序,可以使用TCP,比如FTP协议、HTTP协议。
- 如果主要关注的是速度和实时性,而且不在意某些数据包的丢失,可以选使用UDP协议,比如直播、视频会议等场景。
TCP和UDP可以使用同一个端口吗?
在数据链路层,通过MAC地址来寻找局域网中的主机。在网际层,通过IP地址来寻找网络中互连的主机或路由器。在传输层,需要通过端口进行寻址,来识别同一计算机中同时通信的不同应用程序。
所以,传输层的端口号的作用,是为了区分同一个主机上不同应用程序的数据包。
传输层有两个传输协议分别是TCP和UDP,在内核中是两个完全独立的软件模块。
当主机收到数据包后,可以在IP包头的协议号字段知道该数据包是TCP/UDP,所以可以根据这个信息确定送给哪个模块处理,送给TCP/UDP模块的报文根据端口号确定送给哪个应用程序。
因此,TCP/UDP各自的端口也相互独立,如TCP有一个80端口UDP也有一个80端口,二者并不冲突。
3、TCP连接建立(三次握手)
TCP是面向连接的协议,所以使用TCP前必须建立连接,而建立连接是通过三次握手来进行的。
第三次握手是可以携带数据的,前两次握手是不可以携带数据的。
通过三次握手能防止历史连接的建立,能减少双方不必要的字眼开销,能帮助双方同步初始化序列号。
为什么每次建立TCP连接的时候,初始化的序列号都不一样呢?
- 为了防止历史报文被下一个相同四元组的连接接收。
- 为了安全性,防止黑客伪造相同序列号的TCP报文被对方接收。
初始序列号ISN是如何随机产生的?
ISN=M+F
- M是一个计时器,这个计时器每隔4微秒加1 。
- F是一个Hash算法,根据源IP、目的IP、源端口、目的端口生成一个随机数。
既然IP层会分片,为什么TCP还需要MSS呢?
- MTU:一个网络包的最大长度,以太网一般为1500字节。
- MSS:除去IP和TCP头部后,一个网络包所能容纳的TCP数据的最大长度。
当IP层有一个超过MTU大小的数据要发送,那么IP层就要进行分片,把数据分片成若干片,保证每一个分片都小于MTU。把一份IP数据报进行分片以后,由目标主机的IP层进行重新组装后,再交给上一层的TCP传输层。
但是,如果一个IP分片丢失,整个IP报文的所有分片都要重传。
因为,IP层本身没有超时重传机制,它由传输层的TCP来负责超时和重传。当某一个IP分片无法组装成一个完整的TCP报文,也就无法将数据报文送到TCP层,所以由IP层进行分片传输,是非常没有效率的。
所以,为了达到最佳的传输效率就在建立连接的时候协商双方的MSS值,当TCP层发现数据超过MSS时,就会进行分片。经过TCP层分片后,如果一个TCP分片丢失,进行重发时也是以MSS为单位的,而不用重传所有的分片,大大增加了效率。
TCP进行了三次握手那么,那么某次握手丢失了会发生什么?
- 第一次握手丢失
- 当客户端和服务端建立TCP连接的时候,首先第一个发送SYN报文,然后进入SYN_SENT状态。若客户端迟迟收不到服务端的SYN-ACK报文(第二次握手),就会触发超时重传机制,重传SYN报文(重传的SYN报文序列号是一样的),重传的次数由tcp_syn_retriex决定,如果还未收到二次握手报文,客户端就断开连接。
- 第二次握手丢失
- 第二次握手的ACK报文,是对第一次握手的确认报文。
- 第二次握手的SYN报文,是服务端发起建立的TCP连接的报文。
- 第三次握手丢失
- 重传SYN-ACK报文
4、TCP连接断开(四次挥手)
四次挥手:
第一次挥手丢失,会发生什么?
- 客户端会发生超时重传,若达到最大次数,还没有收到服务端的ACK报文,则客户端断开连接。
第二次挥手丢失,会发生什么?
- ACK报文是不会重传的,所以服务端的第二次挥手丢了,就会触发客户端超时重传机制,重传Fin报文,若达到最大次数,则客户端断开连接。
第三次挥手丢失,会发生什么?
- 服务端处于CLOSE_WAIT状态,调用CLOSE函数,内核就会发出fin报文,同时连接进入LAST_ACK状态,等待客户端返回ACK来确认连接关闭。
第四次挥手丢失,会发生什么?
- 服务端重传fin报文,若第三次挥手报文达到了最大次数,在等一段时间,如果还没收到客户端的第四次挥手ACK报文,那么服务端就会断开连接。
- 客户端在收到第三次挥手之后,就会进入TIME_WAIT状态,开启时长为2MSL的定时器,如果途中再次收到第三次挥手FIN报文,就会重置定时器,当等待2MSL后,客户端就会断开连接。
为什么需要四次挥手?
- 关闭连接时,客户端向服务端发送Fin时,仅仅表示客户端不再发送数据了但是还能接收数据。
- 服务端收到客户端的Fin报文时,先回一个ACK应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送Fin报文给客户端来表示同意现在关闭连接。
- 服务端通常需要等待完成数据的发送和处理,所以服务端的ACK和Fin一般都会分开发送,因此需要四次挥手。
为什么TIME_WAIT等待的时间是2MSL?
MSL:Maximum Segment Lifetime,报文最大生存时间。
是在第三次挥手的时候发送fin报文给客户端,然后客户端进入TIME_WAIT,并发送给服务端ACK报文。
所以,2MSL的时间是从客户端接收到fin后发送ACK到服务端开始计时的。如果TIME_WAIT时间内,因为客户端ACK没有传输到服务端,客户端有接收到了fin,那么2MSL会重新计时。
为什么需要TIME_WAIT状态?
主动发起的一方才会有TIME_WAIT状态。
- 防止历史连接的数据,被后面相同四元组的连接错误的接收。
- 保证被动关闭连接的一方,能被正确关闭。
服务器出现大量CLOSE_WAIT状态有哪些原因?
CLOSE_WAIT状态是被动关闭方才会有的状态,而且如果被动关闭方没有调用CLOSE函数关闭连接,那么就无法发出fin报文,从而无法使得CLOSE_WAIT状态的连接转变为LAST_ACK状态。
解密三次握手四次挥手
当服务端在TCP挥手的过程中,如果没有数据要发送并且开启了TCP延迟确认机制,那么第二和第三次挥手就会合并传输,这样就出现了三次挥手。
通常情况下,服务端收到客户端的fin后,很可能还没发送完数据,所以就先回复客户端一个ACK,稍等一会后,完成所有数据包的发送后,才会发送fin包,这就是四次挥手了。
4.重传机制
TCP实现可靠传输的方式之一,是通过序列号与确认应答。
- 超时重传
- 数据报丢失
- 确认应答丢失
- 快速重传
- SACK
- 在头部加一个SACK字段,可以将已收到的数据信息发送给发送方
- D-SACK
RTT,Round-Trip Time 往返时延,就是数据发送到接收时的时间差值。
5.滑动窗口
窗口的大小是指无需等待确认应答,而可以继续发送数据的最大值。
窗口大小由TCP头部的Window,由接收方的窗口大小所决定的。
TCP滑动窗口使用三个指针来跟踪在四个传输类别中的每一个类别中的字节。其中两个指针是绝对指针(指特定的序列号),一个是相对指针(需要做偏移)。
- SND.WND:表示发送窗口的大小,大小由接收方决定。
- SND.UNA:是一个决对指针,它指向的是已发送但未收到确认的第一个字节序列号。
- SND.NXT:也是一个决对指针,他指向未发送但可发送范围的第一个字节的序列号。
可以窗口大小 = SND.WND - (SND.NXT - SND.UNA)
6.流量控制|拥塞控制
。
参考资料
https://xiaolincoding.com/network/