TCP和UDP
TCP报文格式
TCP首部的报文格式如下:
宏观上来看如下:
- 来源连接端口(16位长)-识别发送连接端口
- 目的连接端口(16位长)-识别接收连接端口
- 序列号(seq,32位长):
- 如果含有同步化旗标(SYN),则此为最初的序列号;第一个数据比特的序列码为本序列号加一。
- 如果没有同步化旗标(SYN),则此为第一个数据比特的序列码。
- 确认号(ack,32位长)— 期望收到的数据的开始序列号。也即已经收到的数据的字节长度加1。
- 数据偏移(4位长)— 以4字节为单位计算出的数据段开始地址的偏移值。
- 保留(3比特长)— 须置0
- 标志符(9比特长)
- NS—ECN-nonce。ECN显式拥塞通知(Explicit Congestion Notification)是对TCP的扩展,定义于RFC 3540(2003)。ECN允许拥塞控制的端对端通知而避免丢包。ECN为一项可选功能,如果底层网络设施支持,则可能被启用ECN的两个端点使用。在ECN成功协商的情况下,ECN感知路由器可以在IP头中设置一个标记来代替丢弃数据包,以标明阻塞即将发生。数据包的接收端回应发送端的表示,降低其传输速率,就如同在往常中检测到包丢失那样。
- CWR—Congestion Window Reduced,定义于RFC 3168(2001)。
- ECE—ECN-Echo有两种意思,取决于SYN标志的值,定义于RFC 3168(2001)。
- URG—为1表示高优先级数据包,紧急指针字段有效。
- ACK—为1表示确认号字段有效
- PSH—为1表示是带有PUSH标志的数据,指示接收方应该尽快将这个报文段交给应用层而不用等待缓冲区装满。
- RST—为1表示出现严重差错。可能需要重新创建TCP连接。还可以用于拒绝非法的报文段和拒绝连接请求。
- SYN—为1表示这是连接请求或是连接接受请求,用于创建连接和使顺序号同步
- FIN—为1表示发送方没有数据要传输了,要求释放连接。
- 窗口(WIN,16位长)—表示从确认号开始,本报文的发送方可以接收的字节数,即接收窗口大小。用于流量控制。
- 校验和(Checksum,16位长)—对整个的TCP报文段,包括TCP头部和TCP数据,以16位字进行计算所得。这是一个强制性的字段。
- 紧急指针(16位长)—本报文段中的紧急数据的最后一个字节的序号。
- 选项字段—最多40字节。每个选项的开始是1字节的kind字段,说明选项的类型。
- 0:选项表结束(1字节)
- 1:无操作(1字节)用于选项字段之间的字边界对齐。
- 2:最大报文段长度(4字节,Maximum Segment Size,MSS)通常在创建连接而设置SYN标志的数据包中指明这个选项,指明本端所能接收的最大长度的报文段。通常将MSS设置为(MTU-40)字节,携带TCP报文段的IP数据报的长度就不会超过MTU(MTU最大长度为1518字节,最短为64字节),从而避免本机发生IP分片。只能出现在同步报文段中,否则将被忽略。
- 3:窗口扩大因子(3字节,wscale),取值0-14。用来把TCP的窗口的值左移的位数,使窗口值乘倍。只能出现在同步报文段中,否则将被忽略。这是因为现在的TCP接收数据缓冲区(接收窗口)的长度通常大于65535字节。
- 4:sackOK—发送端支持并同意使用SACK选项。
- 5:SACK实际工作的选项。
- 8:时间戳(10字节,TCP Timestamps Option,TSopt)
- 发送端的时间戳(Timestamp Value field,TSval,4字节)
- 时间戳回显应答(Timestamp Echo Reply field,TSecr,4字节)
参考:https://baike.baidu.com/item/TCP%E6%8A%A5%E6%96%87%E6%A0%BC%E5%BC%8F/53100036?fr=aladdin
WireShark抓包TCP三次握手
- 第一次握手:客户端向服务端发送SYN包到服务器,并进入SYN_SNET状态,等待服务器确认。
- 第二次握手:服务器收到SYN包之后,必须先确认客户端的SYN包,同时自己也发一个SYN包,即一次发送ACK+SYN的包给到客户端,此时服务器进入SYN_RECV状态
- 第三次握手:客户端收到服务器的ACK+SYN包之后,向服务器端发送ACK包。
第三次握手完成之后,客户端和服务器端都进入ESTABLISHED状态。
为什么客户端还要发送最后一次确认呢?
主要是为了防止已经失效的连接请求报文突然又传送到了服务端,因而产生错误。
所谓「已经失效的连接请求报文」是这样产生的:客户端发送的第一个连接请求报文段没有丢失,而是在某些网络结点长时间滞留了,导致延误到连接释放以后的某个时刻才到达服务端。本来这是一个已经失效的报文,但是服务端接收到此请求报文之后,被误认为是客户端又发出一次新的连接请求,于是又向客户端发送确认报文,同意建立连接。假设没有最后一次握手,那么只要服务端发出确认,新的连接就建立了。
由于现在客户端并没有发出建立连接的请求,因此不会理睬服务端的确认,也不会向服务端发送数据。但是服务端却以为新的连接已经建立了,并一直等待客户端发来数据,服务端的许多资源就这样白白浪费了。
WireShark抓包TCP四次挥手
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qcs6eLJL-1645629776637)(C:\Users\HideOnBush\Desktop\开发笔记\计算机网络\HTTP报文\TCP四次挥手.png)]
- 第一次挥手:客户端进程发出释放报文,并且停止发送数据。释放数据报文首部之后,向服务端发送FIN包到服务器,并进入FIN_WAIT_1状态,即半关闭状态,等待服务器确认,但这个时候客户端仍然可以收到服务端发送过来的数据,只是停止自己这边发送给服务器数据。
- 第二次挥手:服务器收到FIN包之后,确认了客户端想要释放连接,随后服务器端会发送一个ACK包给客户端确认自己收到了此次客户端的FIN包,并随之进入了CLOSE_WAIT状态。客户端收到了服务端发来的ACK确认报文之后就会进入FIN_WAIT_2状态。
- 第三次挥手:服务器端发送ACK确认报文之后,经过CLOSE_WAIT阶段之后,做好了释放服务器端到客户端的连接准备,再次向客户端发送一个FIN报文。随后服务器端结束CLOSE_WAIT阶段,进入了LAST_ACK状态。
- 第四次挥手:客户端收到了服务器端发出的FIN报文,确认了服务器端已经做好释放连接的准备,向服务器端发送确认报文将ACK置为1之后进入TIME_WAIT阶段。
- 客户端在TIME_WAIT阶段之后经过2MSL时间段之后就进入了CLOSED阶段,服务器端在收到了客户端发送来的ACK确认报文段之后也进入了CLOSED阶段。
为什么要客户端要等待2MSL呢?
为的是
- (1)为了保证客户端发送的最后一个ACK报文段能够到达服务端。
- (2)确保由于网络堵塞等原因迟到且客户端重发的消息在本次连接中作废掉,而不会进入下一次连接中。
当客户端发出最后的ACK确认报文时,并不能确定服务器端能够收到该段报文。所以客户端在发送完ACK确认报文之后,会设置一个时长为2MSL的计时器。MSL指的是Maximum Segment Lifetime:一段TCP报文在传输过程中的最大生命周期。2MSL即是服务器端发出为FIN报文和客户端发出的ACK确认报文所能保持有效的最大时长。
服务器端在1MSL内没有收到客户端发出的ACK确认报文,就会再次向客户端发出FIN报文;
如果客户端在2MSL(Maximum Segment Lifetime 最长报文段寿命)内,再次收到了来自服务器端的FIN报文,说明服务器端由于各种原因没有接收到客户端发出的ACK确认报文。客户端再次向服务器端发出ACK确认报文,计时器重置,重新开始2MSL的计时;否则客户端在2MSL内没有再次收到来自服务器端的FIN报文,说明服务器端正常接收了ACK确认报文,客户端可以进入CLOSED阶段,完成“四次挥手”。
所以,客户端要经历时长为2SML的TIME-WAIT阶段;这也是为什么客户端比服务器端晚进入CLOSED阶段的原因
还有TCP三次握手和四次挥手带来的一些在实际工程中的排查问题,以及UDP的介绍,明天补充上。
TCP和UDP的差异点:
TCP的主要特点:
- TCP是面向连接的传输层协议。
- 每一条TCP连接只能有两个端点,每一条TCP连接都只能是点对点的(一对一)
- TCP提供可靠交付的服务。通过TCP连接传送的数据无差错、不丢失、不重复,且按序到达。
- TCP提供全双工通信。TCP允许通信双方的应用进程在任何时候都能发送数据。
- TCP是面向字节流的。TCP中的“流”指的是流入到进程或者从进程中流出的字节序列。
UCP的主要特点:
- UDP是无连接的,即发送数据之前是不建立连接的。
- UCP不保证可靠交付。
- UDP是面向报文的。
- UDP没有拥塞控制
- UCP支持一对一、一对多、多对一和多对多的交互通信。
- UDP首部的开销小,只有8个字节。比TCP的20个字节的首部要短。