TCP报文
tcp详解、tcp与udp对比等
TCP:传输控制协议
UDP:用户数据报协议
源端口和目的端口字段:各占 2 字节(16位)。端口是运输层与应用层的服务接口。运输层的复用和分用功能都要通过端口才能实现。
序列号:在建立连接时由计算机生成的随机数作为其初始值,通过 SYN 包传给接收端主机,每发送一次数据,就「累加」一次该「数据字节数」的大小。用来解决网络包乱序问题。
确认应答号:指下一次「期望」收到的数据的序列号,发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。用来解决丢包的问题。
数据偏移(即首部长度):占 4 位,它指出 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远,也就是TCP首部的长度。“数据偏移”的单位是 32 位字(以 4 字节为计算单位),最大1111表示15x4=60个字节,即表示TCP首部最大长度为60个字节,因此“选项”部分最多40个字节。
保留字段:占 6 位,保留为今后使用,但目前应置为 0。
控制位:
- ACK:该位为 1 时,「确认应答」的字段变为有效,TCP 规定除了最初建立连接时的 SYN 包之外该位必须设置为 1 。
- RST:该位为 1 时,表示 TCP 连接中出现异常必须强制断开连接并进行连接重置
- SYN:该位为 1 时,表示希望建立连接,并在其「序列号」的字段进行序列号初始值的设定。
- FIN:该位为 1 时,表示今后不会再有数据发送,希望断开连接。当通信结束希望断开连接时,通信双方的主机之间就可以相互交换 FIN 位为 1 的 TCP 段。
- 紧急 URG —— 当 URG = 1 时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据)。 即URG=1的数据包不用排队直接优先传输。
- PSH:推送(不需要缓冲到内存直接交给CPU处理)
窗口大小:接收窗口的大小,实际上也就是接收缓存能够容纳对方发来多少数据,窗口字段长度是16位,因此最大的窗口大小为64K字节
检验和 :占 2 字节。检验和字段检验的范围包括首部和数据这两部分。在计算检验和时,要在TCP 报文段的前面加上 12 字节的伪首部。
紧急指针字段 : 占 16 位,指出在本报文段中紧急数据共有多少个字节(紧急数据放在本报文段数据的最前面)。
可选项(长度可变),其中可选项有:最大报文段长度(MSS);用户超时(UTO);窗口缩放(WSOPT)
- MSS:TCP 的数据大小如果大于 MSS 大小,则会在传输层进行分片,目标主机收到后,也同样在传输层组装 TCP 数据包,如果中途丢失了一个分片,只需要传输丢失的这个分片,默认为536。
- WSOPT:提供窗口的大小,用于在TCP连接的一端对另端进行流量控制。
- 用户超时(UTO)
Date:数据
TCP三次握手与四次断开
三次握手
- 一开始,客户端和服务端都处于 CLOSE 状态。先是服务端主动监听某个端口,处于 LISTEN 状态
- 客户端:请求:SYN变成1,sn=100(随机生成的报文序列号发送过去),之后客户端处于 SYN-SENT 状态。
- 服务端:响应:SYN变为1,ACK=1,an=101(表示可以发送下一个了),sn=300(接受方再生成一个报文序确认号),之后服务端处于 SYN-RCVD 状态。
- 客户端:确认(互相确认):ACK=1,sn=101,an=301,之后客户端处于 ESTABLISHED 状态。
- 服务端收到客户端的应答报文后,也进入 ESTABLISHED 状态。
- 一旦完成三次握手,双方都处于ESTABLISHED状态,此时连接就已建立完成,客户端和服务端就可以相互发送数据了。
三次握手数据丢失
(注意:ACK 报文是不会重传的)
第一次握手丢失客户端会重试5次后断开
第二次握手丢失
客户端以为服务端没收到所以进行第一次握手动作5次后断开
服务端会进行第二次握手动作五次会后断开
第三次握手丢失(ACK 报文是不会重传的)服务端会进行第二次握手动作五次后断开
四次挥手
第一次:客户端请求断开FIN,seq=u,之后客户端进入 FIN_WAIT_1 状态。
第二次:服务器确认客户端的断开请求ACK,ack=u+1,seq=v,接着服务端进入 CLOSE_WAIT 状态;客户端收到服务端的 ACK 应答报文后,之后进入 FIN_WAIT_2 状态。
第三次:等待服务端处理完数据后,服务端请求断开FIN,seq=w,ACK,ack=u+1,之后服务端进入 LAST_ACK 状态。
第四次:客户端收到服务端的 FIN 报文后,回一个 ACK 应答报文:ACK,ack=w+1,seq=u+1,之后进入 TIME_WAIT 状态
服务端收到了 ACK 应答报文后,就进入了 CLOSE 状态,至此服务端已经完成连接的关闭。
客户端在经过 2MSL 一段时间后,自动进入 CLOSE 状态,至此客户端也完成连接的关闭。注意主动关闭连接的,才有 TIME_WAIT 状态。
四次挥手时数据丢失
第一次挥手丢失
当客户端(主动关闭方)调用 close 函数后,就会向服务端发送 FIN 报文,试图与服务端断开连接,此时客户端的连接进入到 FIN_WAIT_1 状态。正常情况下,如果能及时收到服务端(被动关闭方)的 ACK,则会很快变为 FIN_WAIT2状态。如果第一次挥手丢失了,那么客户端迟迟收不到被动方的 ACK 的话,也就会触发超时重传机制,重传 FIN 报文,重发次数由 tcp_orphan_retries 参数控制。
当客户端重传 FIN 报文的次数超过 tcp_orphan_retries 后,就不再发送 FIN 报文,则会在等待一段时间(时间为上一次超时时间的 2 倍),如果还是没能收到第二次挥手,那么直接断开连接。
第二次挥手丢失
因为ACK报文是不会重传的所以如果服务端的第二次挥手丢失了,客户端就会触发超时重传机制,重传 FIN 报文,直到收到服务端的第二次挥手,或者达到最大的重传次数等待一段时间后断开。
第三次挥手丢失
服务端:当服务端(被动关闭方)收到客户端(主动关闭方)的 FIN 报文后,内核会自动回复 ACK,同时连接处于 CLOSE_WAIT 状态,顾名思义,它表示等待应用进程调用 close 函数关闭连接。此时,内核是没有权利替代进程关闭连接,必须由进程主动调用 close 函数来触发服务端发送 FIN 报文。服务端处于 CLOSE_WAIT 状态时,调用了 close 函数,内核就会发出 FIN 报文,同时连接进入 LAST_ACK 状态,等待客户端返回 ACK 来确认连接关闭。如果迟迟收不到这个 ACK,服务端就会重发 FIN 报文,重发次数仍然由 tcp_orphan_retries 参数控制,这与客户端重发 FIN 报文的重传次数控制方式是一样的。当服务端重传第三次挥手报文的次数达到了 3 次后,由于 tcp_orphan_retries 为 3,达到了重传最大次数,于是再等待一段时间(时间为上一次超时时间的 2 倍),如果还是没能收到客户端的第四次挥手(ACK报文),那么服务端就会断开连接。
客户端:客户端因为是通过 close 函数关闭连接的,处于 FIN_WAIT_2 状态是有时长限制的,如果 tcp_fin_timeout 时间内还是没能收到服务端的第三次挥手(FIN 报文),那么客户端就会断开连接。
第四次挥手丢失
客户端:当客户端收到服务端的第三次挥手的 FIN 报文后,就会回 ACK 报文,也就是第四次挥手,此时客户端连接进入 TIME_WAIT 状态。在 Linux 系统,TIME_WAIT 状态会持续 2MSL 后才会进入关闭状态。
服务端:服务端(被动关闭方)没有收到 ACK 报文前,还是处于 LAST_ACK 状态。如果第四次挥手的 ACK 报文没有到达服务端,服务端就会重发 FIN 报文,重发次数仍然由前面介绍过的 tcp_orphan_retries 参数控制。当服务端重传第三次挥手报文达到 2 时,由于 tcp_orphan_retries 为 2, 达到了最大重传次数,于是再等待一段时间(时间为上一次超时时间的 2 倍),如果还是没能收到客户端的第四次挥手(ACK 报文),那么服务端就会断开连接。
TCP最大连接数与文件打开数限制
源地址和目的地址的字段(32位)是在 IP 头部中,作用是通过 IP 协议发送报文给对方主机。
源端口和目的端口的字段(16位)是在 TCP 头部中,作用是告诉 TCP 协议应该把报文发给哪个进程。
因此,客户端 IP 和 端口是可变的,其理论值计算公式如下:
最大TCP连接数 = 客户端的IP数 × 客户端的端口数
对 IPv4,客户端的 IP 数最多为 2 的 32 次方,客户端的端口数最多为 2 的 16 次方,也就是服务端单机最大 TCP 连接数,约为 2 的 48 次方。
服务端最大并发 TCP 连接数远不能达到理论上限,会受以下因素影响:
(1)文件描述符限制
每个 TCP 连接都是一个文件,如果文件描述符被占满了,会发生 too many open files。Linux 对可打开的文件描述符的数量分别作了三个方面的限制:
系统级:当前系统可打开的最大数量,通过 cat /proc/sys/fs/file-max 查看;
用户级:指定用户可打开的最大数量,通过 cat /etc/security/limits.conf 查看;
进程级:单个进程可打开的最大数量,通过 cat /proc/sys/fs/nr_open 查看;
(2)id的上限制
vim /etc/sysctl.conf
kernel.pid_max = 1000000
cat /proc/sys/kernel/pid_max
(2)内存限制,每个 TCP 连接都要占用一定内存,操作系统的内存是有限的,如果内存资源被占满后,会发生 OOM。
keepalive机制
- 长连接与短连接的区别
操作方式不同。长连接是指在客户端和服务器之间保持一个持久的连接,数据可以随时在两者之间传输,无需每次都建立新的连接;短连接是指在每次数据传输完成后立即关闭连接,不会保持长时间的连接状态。
资源消耗不同。长连接虽然提高了通信效率和稳定性,但会持续占用资源;短连接在每次数据传输后断开,可以节省资源,但在频繁传输数据时会导致额外的开销。
适用场景不同。长连接适用于需要实时通信和长时间保持连接的场景,如聊天室、实时游戏、数据库连接等;短连接适用于一次性或数据刷新频度较低的场景,如网页浏览、HTTP请求等。
- TCP保活机制
定义一个时间段,在这个时间段内,如果没有任何连接相关的活动,TCP 保活机制会开始作用,每隔一个时间间隔,发送一个探测报文,该探测报文包含的数据非常少,如果连续几个探测报文都没有得到响应,则认为当前的 TCP 连接已经死亡,系统内核将错误信息通知给上层应用程序。
如果开启了 TCP 保活,需要考虑以下几种情况:
第一种,对端程序是正常工作的。当 TCP 保活的探测报文发送给对端, 对端会正常响应,这样 TCP 保活时间会被重置,等待下一个 TCP 保活时间的到来。
第二种,对端程序崩溃并重启。当 TCP 保活的探测报文发送给对端后,对端是可以响应的,但由于没有该连接的有效信息,会产生一个 RST 报文,这样很快就会发现 TCP 连接已经被重置。
第三种,是对端程序崩溃,或对端由于其他原因导致报文不可达。当 TCP 保活的探测报文发送给对端后,石沉大海,没有响应,连续几次,达到保活探测次数后,TCP 会报告该 TCP 连接已经死亡。
- keepalive
TCP 保活的这个机制检测的时间是有点长,我们可以自己在应用层实现一个心跳机制。比如,web 服务软件一般都会提供 keepalive_timeout 参数,用来指定 HTTP 长连接的超时时间。如果设置了 HTTP 长连接的超时时间是 50 秒,web 服务软件就会启动一个定时器,如果客户端在完成一个 HTTP 请求后,在 50 秒内都没有再发起新的请求,定时器的时间一到,就会触发回调函数来释放该连接。在一个连接上执行多个请求,这个就是所谓的长连接。(注意:keepalive是tcp层长连接探活机制;keep-alive是应用层http协议使用,在其头部Connection字段中的一个值,只是代表客户端与服务之间需要保持长连接,可以理解为通过此字段来告诉nginx此连接需要维持长连接,处理完别直接关闭连接。)
- 是否可使用长连接的条件是什么?
客服端的请求头中的connection为close,则客户端要求不使用长连接。
客户端的请求头中的connection为keep-alive,则客户端要求使用长连接。
客户端的请求头中没有connection这个头,如果是http1.0协议默认为close,如果是http1.1协议默认为keep-alive
- keepalive_timeout
长连接时,Nginx在输出完响应体后,会设置当前连接的keepalive属性,然后等待客户端的下一次请求,同时也设置了一个最大等待时间,这个时间通过keepalive_timeout来配置,如果是0,则表示关掉长连接,此时不管客户端的connection值是什么都会强制设为close。
tcpdump命令使用详解
参考文档:https://www.cnblogs.com/howhy/p/6396664.html
wireshark抓包分析工具的安装与使用
Wireshark安装下载
下载地址:http://wireshark.org/download.
windos安装Wireshark
-
以管理员身份运行安装包。
-
这里第二个选项为创建桌面图标,可按照自己的情况选择,其余的保持默认。
-
安装路径选择。
-
这里需要安装NPcap,如果电脑上已安装的可忽略。
wireshark的使用
包内容界面介绍
tcp包的具体内容
报文错误分析参考文档:https://blog.csdn.net/qq_43148894/article/details/120038136