目录索引
send函数和recv函数
write()/read() 与 send()/recv() 的区别
- 由于两组函数的都能通过文件描述符收发网络数据,所以两组函数在功能上有一定的重叠;
- 但是,send/recv函数在数据收发上功能更专业更齐全;
函数原型
- 头文件包含:
#include <sys/socket.h>
- 函数原型:
ssize_t send(int sockfd,const void * buf, size_t nbytes, int flags);
ssize_t recv(int sockfd,void * buf, size_t nbytes, int flags);
- flags:收发数据时指定的可选信息;
– 当flags为0时, send等待发送缓冲区清空后把数据放入缓冲区再返回(有可能等待),recv等待数据缓冲区有数据后获取再返回(有可能等等待);
– 当flags为0时, send()/recv() 在功能上等价于 write()/read() ; - flags可选配置:
可选项 | 含义 | send | recv |
---|---|---|---|
MSG_OOB | 用于传输带外数据(Out Of Band data),即:紧急数据 | ✔ | ✔ |
MSG_PEEK | 窥探接收缓冲区是否存在数据 | ✔ | |
MSG_DONTROUTE | 数据传输过程不通过路由,在本地局域网中寻找目的地 | ✔ | |
MSG_DONTWAIT | 非阻塞模式,数据收发时立即返回 | ✔ | ✔ |
MSG_WAITALL | 在接收到请求的全部数据之前,不提前返回 | ✔ | |
MSG_MORE | 有更多数据需要发送,指示内核等待数据 | ✔ | |
… | … | … | … |
– 注意:不同操作系统对可选项的支持不同,实际工程开发时,需要事先对目标系统中支持的可选项进行调研;
MSG_OOB(带外数据/紧急数据)
- 原生定义:
– 使用与普通数据不同的通道独立传输数据;
– 带外数据优先级比普通数据高(优先传输,对端优先接收); - TCP中的带外数据:
– 由于原生设计的限制,TCP无法提供真正意义上的带外数据;
– TCP中仅能通过传输协议消息头中的标记传输紧急数据,且长度仅1字节; - TCP带外数据实现的原理:
… | URG | URG指针 | … | 0x01 | 0x02 | 带外数据 | URG指针指向的位置 | … |
---|
– URG指针指向紧急消息的下一个位置,即:URG指针指向位置的前一个字节
存粗了紧急数据;
– 紧急数据会放在有别于普通数据的特殊数据缓冲区;
- TCP带外数据的处理策略:
– 由于TCP设计为流式数据,因此,无法做到真正的带外数据;
– 被标记的紧急数据可被提前接收,进入特殊缓冲区
(仅1个字节);
· 每个TCP包最多只有一个紧急数据;
· 特殊缓冲区仅存放最近的紧急数据(不及时接收将丢失); - 使用select接收紧急数据:
– socket上收到普通数据和紧急数据时都会使得select立即返回(通过FD_ISSET监测 select返回的exceptset参数来判断是否是紧急数据);
· 普通数据:socket处于数据可读状态(可读取普通数据);
· 紧急数据:socket处于处理异常状态(可读取紧急数据); - 总结:
– read/write函数可用于收发普通数据(不具备扩展功能);
– send/recv可通过选项信息扩展更多功能;
– TCP紧急数据可标识256(1个字节,2^8)种紧急事件(异常事件);
– 通过select能够及时处理紧急数据并区分普通数据;
MSG_PEEK(数据窥探)
- recv()专用选项,可用于数据预接收;
- 指定MSG_PEEK选项时,不会清空缓冲区;
- 可用于获取接收缓冲区中的数据量(字节数);
MSG_DONTWAIT(立即收发模式)
- 数据收发时不阻塞,立即返回;
- send() :如果无法将数据送入发送缓冲区,那么直接错误返回;
- recv() :如果接收缓冲区中没有数据,那么直接错误返回;
- send()/recv()返回值:-1:错误发生,0:对端调用close()关闭连接,n:发送/接收的数据量;
阻塞发送模式(flags: 0)
- send():
– 发送数据长度 > 发送缓冲区长度 :返回错误
;
– 发送数据长度 <= 发送缓冲区剩余长度 :复制数据到发送缓冲区
;
– 发送缓冲区剩余长度<发送数据长度<=发送缓冲区长度 :等待发送缓冲区清空
; - recv():
– 接收缓冲区中没有数据时:等待数据
;
– 接收缓冲区数据量 <= 接收区长度 :数据全部拷贝到接收区
;
– 接收缓冲区数据量 > 接收区长度 :拷贝部分数据到接收区
;
MSG_WAITALL(等待数据)
- 接收专用,等待需要的数据量完全满足时,recv()才返回;
MSG_MORE(更多数据)
- 发送专用,指示内核不要着急将发送缓冲区中的数据进行传输;