在涉及套接字的I/O操作上设置超时的方法有以下3种:
- 调用alarm函数。
- 在select中阻塞等待I/O,以此代替直接阻塞在read或write调用上。
- 使用SO_RCVTIMEO和SO_SNDTIMEO套接字选项。
上述三个技术都适用于输入和输出操作。但我们希望上述技术不仅仅用于输入和输出操作,还希望将其用于connect函数,因为TCP内置的connect超时相当长(典型值为75秒)。select函数可以用于判断connect是否超时,但其先决条件是套接字处于非阻塞模式。第三种方法对connect函数并不适用。
前两种技术适用于任何描述符,而第三种技术仅适用于套接字描述符。
使用alarm函数设置connect的超时时限的问题在于仅能减少connect的超时时限,但不能延长内核现有的时限。
recv和send函数类似于标准的read和write函数,函数原型如下:
#include <sys/socket.h>
extern ssize_t send (int __fd, const void *__buf, size_t __n, int __flags);
extern ssize_t recv (int __fd, void *__buf, size_t __n, int __flags);
其中send、recv与read、write函数的区别在于多出了flags选项。
其中flags选项的定义位于/usr/include/x86_64-linux-gnu/bits/socket.h中。其中有如下几个选项与我们的需要密切相关。
- MSG_DONTWAIT:本标志在无需打开相应套接字的非阻塞标志的前提下,把单个I/O操作临时指定为非阻塞,接着执行I/O操作,然后关闭非阻塞标志。
- MSG_PEEK:本标志适用于recv和recvfrom,它允许我们查看已可读取的数据,而且系统不在recv和recvfrom返回后丢弃这些数据。
- MSG_WAITALL:不要在尚未读入请求数目的字节之前让一个读操作返回。
readv的功能是从fd所指向的文件读入并将结果保存于iovec所指向的缓冲区中。
writev的功能是将多个iovec所指向的缓冲区中的数据写入到fd所指向的文件中。
函数原型如下:
#include <sys/uio.h>
extern ssize_t readv (int __fd, const struct iovec *__iovec, int __count)
__wur;
extern ssize_t writev (int __fd, const struct iovec *__iovec, int __count)
__wur;
readmsg与sendmsg函数原型如下:
#include <sys/socket.h>
extern ssize_t recvmsg (int __fd, struct msghdr *__message, int __flags);
extern ssize_t sendmsg (int __fd, const struct msghdr *__message,
int __flags);
书中还介绍了一种可扩展的轮询大量描述符的方法。select与poll函数存在的一个问题是,每次调用前都需要设置待查询的文件描述符
最后将已经出现过的发送与接收函数进行一个简单的总结
输入函数 | 输出函数 | 特点 |
read | write | 系统调用,TCP通信使用这一对函数 |
recvfrom | sendto | 用于udp协议的收发函数 |
recv | send | 与read、write相比多出了一个参数,可用于设置相应的操作 |
readv | writev | 分散读、集中写 |
recvmsg | sendmsg | 通用函数,recvmsg可用于返回目的IP地址 |