1. TCP 包头结构
-
源端口、目标端口:计算机上的进程要和其他进程通信是要通过计算机端口的,而一个计算机端口 某个时刻只能被一个进程占用,所以通过指定源端口和目标端口,就可以知道是哪两个进程需要通 信。源端口、目标端口是用16位表示的,可推算计算机的端口个数为2^16个,即65536
-
序列号:表示本报文段所发送数据的第一个字节的编号。在TCP连接中所传送的字节流的每一个字节都会按顺序编号。由于序列号由 32 位表示,所以每2^32个字节,就会出现序列号回绕,再次从 0 开始,作用是解决数据包在网络传输中的乱序问题
-
确认号:表示接收方期望收到发送方下一个报文段的第一个字节数据的编号。也就是告诉发送方:我希望你(指发送方)下次发送的数据的第一个字节数据的编号为此确认号,发送方收到确认应答以后,说明在这个序号以前的数据包都已经被成功接收了,作用是确认数据包在传输过程中是否有丢失
-
数据偏移:表示TCP报文段的首部长度,共4位,由于TCP首部包含一个长度可变的选项部分,需要指定这个TCP报文段到底有多长。它指出 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远。该字段的单位是32位(即4个字节为计算单位),4位二进制最大表示15,所以数据偏移也就 是TCP首部最大60字节
-
控制位
-
URG:表示本报文段中发送的数据是否包含紧急数据。后面的紧急指针字段(urgent pointer)只 有当 URG=1 时才有效
-
ACK:表示是否前面确认号字段是否有效。只有当 ACK=1 时,前面的确认号字段才有效。TCP 规定,连接建立后,ACK必须为1,带 ACK 标志的 TCP 报文段称为确认报文段
-
PSH:提示接收端应用程序应该立即从TCP接收缓冲区中读走数据,为接收后续数据腾出空间。如 果为1,则表示对方应当立即把数据提交给上层应用,而不是缓存起来,如果应用程序不将接收到 的数据读走,就会一直停留在TCP接收缓冲区中
-
RST:如果收到一个 RST=1 的报文,说明与主机的连接出现了严重错误(如主机崩溃),必须释放连接,然后再重新建立连接。或者说明上次发送给主机的数据有问题,主机拒绝响应,带 RST 标志的 TCP 报文段称为复位报文段
-
SYN:在建立连接时使用,用来同步序号。当SYN=1,ACK=0时,表示这是一个请求建立连接的报文段;当 SYN=1,ACK=1 时,表示对方同意建立连接。SYN=1,说明这是一个请求建立连接或同意建立连接的报文。只有在前两次握手中SYN才置为 1, 标志的 TCP 报文段称为同步报文段
-
FIN:表示通知对方本端要关闭连接了,标记数据是否发送完毕。如果 FIN=1 ,即告诉对方:“我的数据已经发送完毕,你可以释放连接了”,带 FIN 标志的 TCP 报文段称为结束报文段
-
-
窗口大小:表示现在允许对方发送的数据量,也就是告诉对方,从本报文段的确认号开始允许对方 发送的数据量,达到此值,需要ACK确认后才能再继续传送后面数据,由Window size value * Window size scaling factor(此值在三次握手阶段TCP选项Window scale协商得到)得出此值
-
校验和:提供额外的可靠性
-
紧急指针:标记紧急数据在数据字段中的位置
-
选项部分:其最大长度可根据TCP首部长度进行推算。TCP首部长度用4位表示,选项部分最长 为:(2^4-1)*4-20=40字节
TCP包头常见选项:
-
最大报文段长度MSS(Maximum Segment Size),通常1460字节
指明自己期望对方发送TCP报文段时那个数据字段的长度。比如:1460字节。数据字段的长度加 上TCP首部的长度才等于整个TCP报文段的长度。MSS不宜设的太大也不宜设的太小。若选择太 小,极端情况下,TCP报文段只含有1字节数据,在IP层传输的数据报的开销至少有40字节(包括 TCP报文段的首部和IP数据报的首部)。这样,网络的利用率就不会超过1/41。若TCP报文段非常 长,那么在IP层传输时就有可能要分解成多个短数据报片。在终点要把收到的各个短数据报片装配 成原来的TCP报文段。当传输出错时还要进行重传,这些也都会使开销增大。因此MSS应尽可能 大,只要在IP层传输时不需要再分片就行。在连接建立过程中,双方都把自己能够支持的MSS写入 这一字段。 MSS只出现在SYN报文中。即:MSS出现在SYN=1的报文段中 MTU和MSS值的关系:MTU=MSS+IP Header+TCP Header
通信双方最终的MSS值=较小MTU-IP Header-TCP Header -
窗口扩大 Window Scale
为了扩大窗口,由于TCP首部的窗口大小字段长度是16位,所以其表示的最大数是65535。但是随 着时延和带宽比较大的通信产生(如卫星通信),需要更大的窗口来满足性能和吞吐率,所以产生 了这个窗口扩大选项
-
时间戳 Timestamps
可以用来计算RTT(往返时间),发送方发送TCP报文时,把当前的时间值放入时间戳字段,接收方 收到后发送确认报文时,把这个时间戳字段的值复制到确认报文中,当发送方收到确认报文后即可 计算出RTT。也可以用来防止回绕序号PAWS,也可以说可以用来区分相同序列号的不同报文。因 为序列号用32为表示,每2^32个序列号就会产生回绕,那么使用时间戳字段就很容易区分相同序 列号的不同报文
2. 三次握手
2.1 三次握手图解
2.2 使用 tcpdump 和 wireshark 解读三次握手过程
实际生产中我们可以直接使用 wireshark 进行抓包查看 TCP 的通信过程,本文中使用 tcpdump 和 wireshark 结合, 主要是想顺带演示一下 tcpdump,毕竟在生产中我们使用的大多是 Linux 服务器,查看简单的网络问题,使用命令行模式的 tcpdump 可能会更多一些。
实验环境
centos8 服务端 http 服务的信息如下
[root@centos8 ~]#hostname -I | awk '{print $2}'
10.0.0.11
[root@centos8 ~]# yum -y install httpd
[root@centos8 ~]# yum -y install tcpdump # 需要配置 epel 源
# epel 源配置如下
[root@centos8 ~]#cat /etc/yum.repos.d/epel.repo
[epel]
name=epel
baseurl=https://mirrors.tuna.tsinghua.edu.cn/epel/$releasever/Everything/x86_64
gpgcheck=0
enabled=1
[root@centos8 ~]#
centos7 的客户端机器信息
[root@centos7 ~]# hostname -I|awk '{print $2}'
10.0.0.12
[root@centos7 ~]#
在 centos8 机器上使用 tcpdump 抓包
[root@centos8 ~]#tcpdump -i eth1 -nn -c5 tcp port 80 -w tcp.pcap
dropped privs to tcpdump
tcpdump: listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
5 packets captured
11 packets received by filter
0 packets dropped by kernel
[root@centos8 ~]#
在 cetons7 机器上访问 centos8 的 http 服务
[root@centos7 ~]# curl 10.0.0.11
因为 httpd 服务采用 TCP 协议通信,所以,首先需要三次握手
将保存下来的 tcp.pcap 文件下载到桌面上,使用 wireshark 打开