recv
recv() 是 Linux 网络编程中用于从套接字接收数据的核心函数
#include<sys/socket.h>ssize_trecv(intsockfd,void*buf,size_t len,intflags);参数说明
| 参数 | 说明 |
|---|---|
| sockfd | 套接字描述符(socket descriptor) |
| buf | 接收数据的缓冲区地址 |
| len | 缓冲区最大长度 |
| flags | 接收标志,控制接收行为 |
常用 Flags
// 组合使用时可使用按位或 (|)MSG_WAITALL// 等待所有请求数据到达(阻塞直到收到len字节)MSG_PEEK// 查看数据但不从接收队列移除MSG_OOB// 接收带外数据(out-of-band)MSG_DONTWAIT// 非阻塞接收MSG_NOSIGNAL// 不产生SIGPIPE信号当 recv() 函数的 flags 参数为0时,表示使用默认的接收行为。这是最常用、最简单的调用方式 在实际编程中,约80%的情况使用flags=0,只有在需要特殊行为时才使用其他标志。
默认行为(flags = 0)意味着:
1.阻塞模式
// 如果套接字是阻塞的(默认),recv会一直等待直到:// - 有数据可读// - 连接关闭// - 发生错误ssize_t n=recv(sockfd,buf,len,0);// 阻塞直到有数据2.无特殊标志
不启用以下任何特殊标志:
- ❌ 不查看数据(非MSG_PEEK)
- ❌ 不等待所有数据(非MSG_WAITALL)
- ❌ 非阻塞操作(非MSG_DONTWAIT)
- ❌ 不接收带外数据(非MSG_OOB)
- ❌ 不抑制信号(非MSG_NOSIGNAL)
返回值
- 成功:返回接收到的字节数(可能小于len)
- 返回0:连接已关闭(对端调用close()或shutdown())
- 返回-1:出错,通过errno获取具体错误码
常见问题及解决
- 粘包问题:通过协议设计解决(长度前缀、分隔符)
- 数据不完整:循环接收直到满足需求
- 阻塞时间过长:设置接收超时
send
Linux中send()函数用于通过已连接的套接字发送数据
#include<sys/types.h>#include<sys/socket.h>ssize_tsend(intsockfd,constvoid*buf,size_t len,intflags);参数说明
1.sockfd(套接字描述符)
- 已连接的套接字文件描述符
- 对于TCP,必须是已成功连接(connect())的套接字
- 对于UDP,可以是已连接(connect())的套接字
2.buf(数据缓冲区)
- 指向要发送数据的缓冲区的指针
3.len(数据长度)
- 要发送的数据字节数
4.flags(标志位)
常用标志:
- 0:默认,阻塞模式
- MSG_DONTWAIT:非阻塞操作
- MSG_OOB:发送带外数据
- MSG_NOSIGNAL:连接断开时不产生SIGPIPE信号
- MSG_MORE:提示内核有更多数据要发送(TCP_CORK效果)
返回值
- 成功:返回发送的字节数(可能小于len)
- 失败:返回-1,设置errno
重要特性
1.阻塞 vs 非阻塞
- 阻塞模式:缓冲区满时,send()会阻塞直到可以发送数据
- 非阻塞模式:立即返回EAGAIN/EWOULDBLOCK(非阻塞模式下缓冲区满)
2.部分发送
- send()可能只发送部分数据
- 必须检查返回值并处理剩余数据
3.TCP与UDP的不同
- TCP:保证数据顺序,可能分片
- UDP:消息边界保持,但可能丢失
read、write、recv、send的区别
// 通用的I/O操作ssize_tread(intfd,void*buf,size_t count);ssize_twrite(intfd,constvoid*buf,size_t count);// 套接字专用的I/O操作ssize_trecv(intsockfd,void*buf,size_t len,intflags);ssize_tsend(intsockfd,constvoid*buf,size_t len,intflags);read、write和recv、send只差一个参数flags
主要区别
| 特性 | read/write | recv/send |
|---|---|---|
| 适用范围 | 所有文件描述符 | 仅套接字描述符 |
| 标志位 | 无flags参数 | 有flags参数控制行为 |
| 中断处理 | 可能被信号中断 | 支持MSG_WAITALL等高级选项 |
| 连接状态 | 更通用 | 支持面向连接的语义 |