套接字超时
在设计套接字的IO操作上设置超时的方法有以下三种
1)调用alarm,它在指定超时期慢时产生SIGALRM信号。这个方法设计信号处理,而信号处理在不同实现上
存在差异,而且可能干扰进程中现有的alram调用
2)在select中阻塞等待I/O(select有内置的时间限制),以此代替直接阻塞在read或者write调用上
3)使用交心的SO_RCVTIMEO和SO_SNDTIMEO套接字选项。这个方法的问题在于并发所有实现都支持这
两个套接字选项
以上三个技术都适用于输入和输出操作(如read,write以及recvfrom,sendto之类的变体)
recv和send函数
#include <sys/socket.h> ssize_t recv(int sockfd, void *buff, size_t nbytes, int flags); ssize_t send(int sockfd, const void * buff, size_t nbytes, int flags);
I/O函数的flag参数
flag | 说明 | recv | send |
MSG_DONTROUTE | 绕过路由表查找 本标志高速内核目的主机在某个直接连接的本地网络上,因为无需 执行路由表查找 |
是 | |
MSG_DONTWAIT | 仅本操作非阻塞 本标志在无需打开响应套接字的非阻塞标志的前提下,把单个IO 操作临时定位非阻塞,接着执行IO操作,然后关闭非阻塞标志 |
是 | 是 |
MSG_OOB | 发送或接收带外数据 对于send,本标志指明即将发送带外数据。TCP连接上只有一个 字节可以作为带外数据发送。对于recv本标志指明即将读入的是 带外数据而不是普通数据 |
是 | 是 |
MSG_PEEK | 窥看外来消息 本标志适用于recv和recvfrom,它允许我们查看已可读取的数据, 而且系统不再recv或recvfrom返回后丢弃这些数据 |
是 | |
MSG_WAITALL | 等待所有数据 它告知内核不要在尚未读入请求数目的字节之前让一个读操作返回。 |
是 |
其他的还有MSG_EOR指示逻辑记录的结束
flags参数设计上存在一个基本问题,它是按值传递的而不是值--结果参数。因此它只用于进程向内核传递,而
内核无法向进程传回标志
readv和writev函数
#include <sys/uio.h> ssize_t readv(int filedes, const struct iovec * iov, int iovcnt); ssize_t writev(int filedes, const struct iovec * iov, int iovcnt); //返回: 读到或写出的字节数,出错时为-1 //iovec结构体如下 struct iovec { void *iov_base; //buffer的起始地址 size_t iov_len; //buffer数量 };
recvmsg和sendmsg函数
#include <sys/socket.h> ssize_t recvmsg(int sockfd, struct msghdr * msg, int flags); ssize_t sendmsg(int sockfd, struct msghdr * msg, int flags); //返回: 成功时为读入或写出的字节数,出错时为-1 //这两个函数把大部分参数封装到一个msghdr结构体中 struct msghdr { void *msg_name; /* protocol address */ socklen_t msg_namelen; /* size of protocol address */ struct iovec *msg_iov; /* scatter/gather array */ int msg_iovlen; /* # elements in msg_iov */ void *msg_control; /* ancillary data (cmsghdr struct) */ socklen_t msg_controllen; /* length of ancillary data */ int msg_flags; /* flags returned by recvmsg() */ };
假设从198.6.38.100端口2000达到一个170字节的UDP数据报,它的目标IP地址为206.168.112.96
下图是recvmsg返回时msghdr结构体重的所有信息
1)msg_那么成员指向的缓冲区被填以一个套接字地址结构,其中所有受到数据报的源IP地址和源UDP端口
2)msg_namelen成员(值--结构参数)被更新为存放在msg_name所指缓冲区中的数据量
3)所收取数据报的前100字节数据放在第一个缓冲区中,中间60字节放在第二个缓存区中,最后10个字节数据
放在第三个缓冲区
4)msg_control成员指向的缓冲区被填以一个cmsghdr结构,该cmsghdr结构中,cmsg_len成员值为16,
cmsg_level成员值为IPPROTO_IP,cmsg_type成员值为IP_RECVDSTADDR,随后4个字节存放所有
收到UDP数据报的目的IP地址
5)msg_controllen成员被更新为所存放辅助数据的实际数据量,也是一个值--结果参数
6)msg_flags成员同样被recfmsg更新,不过没有标志返回给进程
五组I/O函数对比
函数 | 任何描述符 | 仅套接字描述符 | 单个读/写缓冲区 | 分散/集中读写 | 可选标志 | 可选对端地址 | 可选控制信息 |
read write |
是 | 是 | |||||
readv writev |
是 | 是 | |||||
recv send |
是 | 是 | 是 | ||||
recvfrom sendto |
是 | 是 | 是 | 是 | |||
recvmsg sendmsg |
是 | 是 | 是 | 是 | 是 |