一、send/recv
send
和 recv
是在网络编程中常用的两个函数,用于在套接字(socket)之间发送和接收数据。
1.send
函数
用于将数据发送到连接的套接字。
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
sockfd
:要发送数据的套接字描述符。buf
:指向要发送数据的缓冲区的指针。len
:要发送的数据字节数。flags
:发送的标志,通常可以设置为 0。-
返回值:成功时返回实际发送的字节数,失败时返回 -1。
2. recv
函数
用于接收来自连接的套接字的数据。
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
sockfd
:要接收数据的套接字描述符。buf
:指向用来存储接收到的数据的缓冲区的指针。len
:要读取的最大字节数。flags
:接收的标志,通常可以设置为 0。-
返回值:成功时返回实际接收到的字节数。如果对方关闭了连接,返回 0;失败时返回 -1。
注意:
- 阻塞与非阻塞:
send
和recv
默认为阻塞模式,但可以将套接字设置为非阻塞模式。 - 数据完整性:
send
和recv
并不保证会发送或接收完整的数据,需根据返回值进行处理,可能需要在循环中调用这些函数以确保完整数据的发送和接收。
二、粘包
粘包问题是网络编程中常遇到的一个问题,尤其是在使用 TCP 协议的情况下。由于 TCP 是一种面向字节流的协议,它不会维护消息边界,可能会导致多个独立发送的数据包在接收方被粘连在一起。
1. 粘包的定义
- 粘包:指的是发送方连续发送了多个数据包,接收方在读取数据时无法区分这些独立的数据包,导致多个数据包粘在一起,形成一个大的数据块。
- 拆包:是指接收方在读取数据时,发现一个完整的数据包被拆分为多个部分,导致难以正确解析。
2. 粘包和拆包的原因
粘包和拆包问题主要由以下几个因素引起:
- TCP 是面向字节流的协议:TCP 接收的数据是一个连续的字节流,没有消息边界的概念。
- 网络延迟:网络的延迟可能会导致多个小的数据包在网络中被合并成一个大包。
-
发送频率:如果发送方频繁地发送小数据包,接收方可能会在缓冲区中接收到这些小包的组合。
3. 解决粘包问题的方法
由于粘包和拆包问题是 TCP 通信中的常见问题,因此需要通过以下方法加以解决:
a. 定长消息
每个数据包都有固定的长度,发送和接收方都知道这一长度。
- 优点:简单明了,不需要额外的逻辑;
- 缺点:不灵活,不能处理可变长度的数据。
b. 使用分隔符
在数据包之间使用特定的字符(如换行符、逗号或其他不可出现的字符)来分隔消息。
- 示例:发送内容为
"Hello\nWorld\n"
,接收方通过换行符来判断消息的结束。 - 优点:实现简单;
- 缺点:需要保证分隔符不在数据内容中。
三、抓包
抓包是指通过特定工具捕获网络中传输的数据包,以便分析其内容、结构和传输状态。抓包可以帮助开发者和网络管理员诊断网络问题、调试应用程序、分析协议等。
常用的抓包软件:
wireshark
TCP报文首部的组成结构
1. TCP 段的组成
一个 TCP 段的结构一般可以划分为以下部分:
- 源端口(Source Port):16 位,表示发送方的端口号。
- 目的端口(Destination Port):16 位,表示接收方的端口号。
- 序列号(Sequence Number):32 位,用于标识字节流中的字节位置,用于确保数据的顺序。
- 确认号(Acknowledgment Number):32 位,表示期望接收的下一个字节的序列号,用于实现可靠性。
- 数据偏移(Data Offset):4 位,指示 TCP 头部的长度(以 32 位字为单位)。
- 保留位(Reserved):6 位,保留供将来使用。
- 控制位(Flags)(6 位):包括以下标志位:
- URG(紧急标志)
- ACK(确认标志)
- PSH(推送标志)
- RST(重置标志)
- SYN(同步标志)
- FIN(结束标志)
- 窗口大小(Window Size):16 位,表示接收方的缓冲区大小。
- 校验和(Checksum):16 位,校验 TCP 段的完整性。
- 紧急指针(Urgent Pointer):16 位,仅在 URG 标志为 1 时有效,指示紧急数据的位置。
- 选项(Options):可变长度,可能包含窗口扩大、时间戳等选项。
- 填充(Padding):确保 TCP 头部的长度是 32 位的倍数。
- 数据(Data):可变长度,包含应用层传输的数据。
2. TCP 标志位的作用
-
URG(紧急标志):
- 表示紧急数据的存在。若设置为 1,接收方会优先处理紧急数据。
-
ACK(确认标志):
- 表示确认号有效。每当接收到数据时,都会发送带有 ACK 标志的包,以确认已收到的数据。
-
PSH(推送标志):
- 表示接收方应立即将数据推送到应用层,而不是等待缓冲区满。适用于需要实时处理的数据。
-
RST(重置标志):
- 用于重置连接。当一方希望强制关闭连接时,会发送带有 RST 标志的包。
-
SYN(同步标志):
- 用于建立连接。在 TCP 三次握手过程中,客户端和服务器通过发送带有 SYN 标志的包来同步序列号。
-
FIN(结束标志):
- 用于结束连接。当一方完成数据传输时,会发送带有 FIN 标志的包,表示希望关闭连接。