recv
和 read
都是用于从文件描述符读取数据的系统调用,但它们的设计目的和使用场景有所不同。以下是两者的主要区别:
1. 设计目的
recv | read |
---|---|
专为套接字(socket)通信设计,属于 Berkeley 套接字 API 的一部分。 | 通用的文件读取接口,属于 POSIX I/O 标准,适用于所有文件描述符(文件、管道、套接字等)。 |
2. 函数原型
// recv 原型(需要包含 <sys/socket.h>)
ssize_t recv(int sockfd, void *buf, size_t len, int flags);// read 原型(需要包含 <unistd.h>)
ssize_t read(int fd, void *buf, size_t count);
read
:
-
read
是一个通用的系统调用,用于从文件描述符中读取数据。它不仅可以用于网络套接字,也可以用于从普通文件或设备读取数据。 -
参数:
-
fd
:文件描述符,可以是普通文件、设备或网络套接字等。 -
buf
:存储读取数据的缓冲区。 -
count
:请求读取的字节数。
-
-
返回值:成功时返回读取的字节数,失败时返回 -1,并设置
errno
。
recv
:
-
recv
是专门用于网络套接字编程的系统调用,通常用于从连接的套接字中读取数据。 -
参数:
-
sockfd
:套接字文件描述符。 -
buf
:存储读取数据的缓冲区。 -
len
:请求读取的字节数。 -
flags
:控制数据接收的标志位,常用的标志有MSG_PEEK
(窥探数据,但不移除)和MSG_WAITALL
(等待完整的消息)。
-
-
返回值:成功时返回读取的字节数,失败时返回 -1,并设置
errno
。
关键区别:
flags
参数:recv
多了一个flags
参数,允许对接收行为进行更精细的控制(见下文)。read
无此参数。
3. 控制选项(flags
)
recv
的 flags
参数支持以下常用选项(按需组合):
标志 | 说明 |
---|---|
MSG_PEEK | 查看数据但不从接收缓冲区移除(下次调用仍会读到相同内容)。 |
MSG_WAITALL | 阻塞直到请求的字节数全部接收完成(除非发生错误或连接关闭)。 |
MSG_OOB | 接收带外数据(Out-of-Band Data,如 TCP 紧急数据)。 |
MSG_DONTWAIT | 非阻塞模式:即使套接字是阻塞的,本次调用也会立即返回(需检查 errno )。 |
read
没有这些控制选项,只能按默认行为读取数据。
4. 返回值与错误处理
recv | read |
---|---|
成功:返回实际接收的字节数(可能小于请求的 len )。连接关闭:返回 0 。错误:返回 -1 ,设置 errno (如 EAGAIN 、ECONNRESET )。 | 成功:返回实际读取的字节数(可能小于请求的 count )。文件结束(EOF):返回 0 。错误:返回 -1 ,设置 errno 。 |
共同行为:
- 两者在非阻塞模式下均可能返回
EAGAIN
或EWOULDBLOCK
(表示当前无数据可读)。
5. 适用场景
recv | read |
---|---|
专门用于套接字通信(TCP/UDP)。需要精细控制接收行为(如窥探数据或接收紧急数据)。 | 适用于所有文件描述符(文件、管道、套接字等)。简单读取数据,无需特殊控制。 |
6. 示例对比
使用 recv
接收数据:
char buffer[1024];
ssize_t n = recv(sockfd, buffer, sizeof(buffer), MSG_PEEK);
if (n == -1) {// 处理错误
} else if (n == 0) {// 连接已关闭
} else {// 处理数据(数据仍在接收缓冲区中)
}
使用 read
读取套接字:
char buffer[1024];
ssize_t n = read(sockfd, buffer, sizeof(buffer));
if (n == -1) {// 处理错误
} else if (n == 0) {// 连接已关闭
} else {// 处理数据(数据已从接收缓冲区移除)
}
7. 关键总结
特性 | recv | read |
---|---|---|
设计目标 | 面向网络通信(套接字) | 通用文件/设备读取 |
控制选项 | 支持 flags 参数 | 无 |
头文件 | <sys/socket.h> | <unistd.h> |
使用场景 | 需精细控制接收行为时 | 简单读取所有类型文件描述符 |
何时选择?
-
优先
recv
:在套接字编程中需要控制接收行为(如窥探数据、接收带外数据或非阻塞操作)。 -
使用
read
:对套接字进行简单读取,或兼容非网络文件描述符(如文件、管道)。