涉及套接字上的I/O操作设置超时的方法有三种方法:
前两种技术可以用于任何描述字,而第三种只能用于套接口描述字。
这两个函数和标准的read和write函数都类似,不过多了一个附加参数
#include <sys/socket.h>
sszie_t recv(int sockfd, void * buff, size_t nbytes, int flags);
ssize_t send(int sockfd, void * buff, size_t nbytes, int flags);
//返回: 成功返回读入或写出的字节数,出错返回-1
flag在设计上存在一个基本问题:它是按值传递的,而不是值-结果参数,因此它只能从进程向内核传递标志,内核不能向进程传递标志。
#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; /* starting address of buffer */
size_t iov_len; /* size of buffer */
}
readv和writev函数可以用于任何描述字,不仅限于套接口描述字,而且writev是一个原子操作。
这两个函数是最通用的I/O函数,实际上,可以用recvmsg代替read, readv, recv, recvfrom. 类似的,各种输出函数可以用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() */
};
辅助数据(ancillary data)可以通过sendmsg和recvmsg这两个函数,使用msghdr结构中的msg_contorl和msg_controllen成员发送和接收。 辅助数据的另一种叫法是控制信息(control information) 辅助数据是一个或多个辅助数据对象组成,每个对象由一个cmsghdr结构开头,该结构在
struct cmsghdr {
socklen_t cmsg_len; /* length in bytes, including this structure */
int cmsg_level; /* originating protocol */
int cmsg_type; /* protocol-specific type */
/* followed by unsigned char cmsg_data[] */
};
下图为在Unix域套接字上的cmsghdr结构:
在不读出数据的情况下,如何知道一个套接口的接收队列中有多少数据可读呢?有三种方法:
标准I/O库执行三种缓冲:
大多数Unix中标准I/O库的实现遵循了以下规则:
既然套接口不是终端设备,上面str_echo函数的问题就在于输出流(fpout)是全缓冲的。 有两种解决方法:调用setvbuf将输出流强制成行缓冲的,或者在每次fputs之后调用fflush强制输出回射行。