TCP协议的报文由两个主要部分组成:TCP首部 和数据部分。TCP首部是控制TCP连接和传输的重要部分,而数据部分则包含了实际要传输的应用层数据。
TCP报文段结构
一个完整的TCP报文段包括TCP首部和数据部分。
TCP首部结构
TCP首部的标准长度是 20 字节(不含可选字段),但由于包含可选字段,首部长度可能会有所增加。标准的TCP首部包含以下字段:
-
源端口号(Source Port,16位):
- 发送方的端口号,用于标识通信的源端。
-
目的端口号(Destination Port,16位):
- 接收方的端口号,用于标识通信的目的端。
-
序列号(Sequence Number,32位):
- 标识这个报文段中的数据在整个数据流中的位置。对于建立连接的第一个报文段,序列号是一个初始序列号(ISN),之后每发送一个字节,序列号就递增。
-
确认号(Acknowledgment Number,32位):
- 用于确认接收的数据。确认号是期望接收的下一个字节的序列号。只有当ACK标志设置时,确认号字段才有效。
-
数据偏移(Data Offset,4位):
- 指定TCP首部的长度,以32位字为单位。最小值为5(表示20字节的基本首部),最大值为15(表示60字节的首部长度)。
-
保留位(Reserved,6位):
- 保留为将来使用,通常设置为0。
-
标志位(Flags,6位):
- 由六个标志位组成,分别是:
- URG(紧急指针有效,Urgent Pointer field significant):表示紧急数据。
- ACK(确认号有效,Acknowledgment field significant):表示确认号字段有效。
- PSH(推送数据,Push Function):提示接收方应尽快将数据推送到应用层。
- RST(重置连接,Reset the connection):表示连接出现问题,需要重新建立连接。
- SYN(同步序列号,Synchronize sequence numbers):用于建立连接时同步序列号。
- FIN(结束连接,No more data from sender):表示发送方已完成数据传输,准备断开连接。
- 由六个标志位组成,分别是:
-
窗口大小(Window Size,16位):
- 表示接收方的接收窗口大小,用于流量控制。它告诉发送方在接收确认之前最多还能发送多少字节的数据。
-
校验和(Checksum,16位):
- 覆盖整个TCP报文段(包括首部和数据)的校验和,用于检测数据传输中的错误。
-
紧急指针(Urgent Pointer,16位):
- 仅当URG标志置位时有效,指出紧急数据的结束位置。
-
选项(Options,可变长):
- 用于在TCP头中添加扩展功能,如最大报文段长度(MSS)、时间戳等。选项字段的长度必须是32位的倍数,不足时用填充(Padding)字段补齐。
-
填充(Padding):
-
填充字段用于确保TCP首部的长度是32位的倍数。
cpp0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Port | Destination Port | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Acknowledgment Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Data | Reser- | Flags | | | Offset| ved | (6 bits) | Window Size | | (4bit)| (6bit)| | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Checksum | Urgent Pointer | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Options (if any) | Padding | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Data (variable) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
数据部分(Data)
- TCP的数据部分长度可变,取决于MTU(最大传输单元)和TCP首部的长度。典型的TCP数据段可能会受到路径MTU的影响,一般来说数据部分的长度不会超过1500字节减去IP和TCP首部的长度。
- TCP首部:控制传输和连接的各种字段。
- 数据部分:实际传输的应用层数据。
TCP编程粘包问题产生的原因
- 发送端发送数据速度过快:在发送端,当数据量较小时,操作系统可能将多次发送的消息合并成一个TCP数据包进行传输。
- 接收端读取不及时:接收端可能因为读取速度跟不上数据的到达速度,从而导致接收到的缓冲区中包含多个消息。
2. 粘包问题的解决方法
2.1 定长消息
- 方法描述: 规定每个消息的长度是固定的,例如每个消息长度为100字节。如果发送的数据不足100字节,则使用填充字符(如空格)补齐。
- 优点: 简单易行,接收方只需要按照固定长度读取数据。
- 缺点: 如果消息长度不固定或者长度变化较大,会导致带宽的浪费,或者需要对消息进行复杂的分割处理。
2.2 添加消息分隔符
- 方法描述 : 在每个消息的末尾添加特殊的分隔符(例如换行符
\n
、空格、特定字符串等),接收方在接收到数据后通过判断分隔符来拆分消息。 - 优点: 灵活,不需要固定消息长度。
- 缺点: 如果消息内容中可能包含分隔符,需要进行转义或避免使用该分隔符。
2.3 消息头标识长度
-
方法描述: 在每个消息前添加一个定长的消息头(通常是4字节或8字节),该消息头指明后续数据的长度。接收方先读取消息头,再根据消息头中指定的长度读取后续的完整消息。
-
优点: 可以处理可变长度的消息,是一种较为常用的解决方案。
-
缺点: 需要增加额外的消息头处理逻辑。
例子:
- 假设消息头长度为4字节,那么在发送数据时:
- 先将消息长度(例如
123
字节)编码为4字节的整数值并发送。 - 接着发送实际的消息数据。
- 先将消息长度(例如
- 接收端:
- 先接收4字节的消息头,并解码出消息长度。
- 然后根据消息长度接收实际的消息内容。
- 假设消息头长度为4字节,那么在发送数据时:
netstat
netstat
(网络统计)是一个用于显示网络连接、路由表、接口统计、伪连接等网络相关信息的命令行工具。它适用于多种操作系统,包括Windows、Linux和macOS。
1. 查看当前网络连接
netstat
2. 查看所有连接及监听端口
netstat -a
3. 查看TCP连接
netstat -at
4. 查看UDP连接
netstat -au
5. 查看程序相关的连接和监听
netstat -p
6. 显示网络接口统计
netstat -i
7. 显示路由表
netstat -r
8. 显示所有信息,并且以数字形式显示地址和端口
netstat -n
- 定期刷新显示
netstat -c
Wireshark 在 Linux 上的安装和使用
1. 安装 Wireshark
-
使用包管理器:
- Debian/Ubuntu :
- 打开终端,运行命令
sudo apt update
更新软件包列表。 - 安装 Wireshark:
sudo apt install wireshark
- 打开终端,运行命令
使用 Wireshark
启动 Wireshark :
-
在终端中运行
wireshark
命令启动 Wireshark GUI,或者通过系统菜单找到并启动它。 -
捕获数据包:
- 在 Wireshark 主界面,选择要监控的网络接口(例如 eth0、wlan0)。
- 点击"Start"按钮开始数据包捕获。
-
停止捕获:
- 要停止数据包捕获,点击工具栏中的"Stop"按钮。
-
分析数据包:
- 捕获的数据包会显示在 Wireshark 窗口中。
- 可以使用过滤器来查找特定的数据包。过滤器可以是协议、源地址、目标地址等。
- 例如,使用
http
过滤器查看 HTTP 数据包,或使用ip.addr == 192.168.1.1
过滤器查看特定 IP 地址的数据包。
- 例如,使用
- 点击数据包查看详细信息,包括协议层次结构和详细的字段信息。
-
保存和加载捕获文件:
- 可以将捕获的数据保存为
.pcap
文件,点击"File" > "Save As" 并选择保存位置。 - 加载保存的捕获文件,可以通过点击"File" > "Open" 选择之前保存的
.pcap
文件。
- 可以将捕获的数据保存为
- Debian/Ubuntu :