UNPv1第十三章:高级IO

1.套接字超时

涉及套接字上的I/O操作设置超时的方法有三种方法:

  1. 调用alarm,在到达指定时间时产生SIGALRM信号
  2. 使用select阻塞在等待I/O上,select内部有一个时间限制,以此代替在read或write调用上阻塞
  3. 使用新的SO_RCVTIMEO和SO_SNDTIMEO套接字选项

前两种技术可以用于任何描述字,而第三种只能用于套接口描述字。

2.recv和send函数

这两个函数和标准的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在设计上存在一个基本问题:它是按值传递的,而不是值-结果参数,因此它只能从进程向内核传递标志,内核不能向进程传递标志。

3.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; /* starting address of buffer */
  size_t iov_len; /* size of buffer */
}

readv和writev函数可以用于任何描述字,不仅限于套接口描述字,而且writev是一个原子操作。

4.recvmsg和sendmsg函数

这两个函数是最通用的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() */
};

5.辅助数据

辅助数据(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结构:
UNPv1第十三章:高级IO_第1张图片

6 排队的数据量

在不读出数据的情况下,如何知道一个套接口的接收队列中有多少数据可读呢?有三种方法:

  1. 如果在没有数据可读时还有其他事情要做,为了不阻塞在内核中,可以使用非阻塞I/O
  2. 如果想检查一下数据而使数据仍留在接收队列中,可以使用MSG_PEEK标志。如果想这样做,但又不能肯定是否有数据可读,可以把这个标志和非阻塞套接口相结合,或与MSG_DONTWAIT标志结合使用。
  3. 一些实现支持ioctl的FIONREAD命令

7.套接口和标准I/O

标准I/O库执行三种缓冲:

  1. 完全缓冲意味着只有在以下情况时才进行I/O:缓冲区满,进程明确地调用fflush或进程调用exit终止。标准I/O缓冲区大小通常为8192字节。
  2. 行缓冲意味着在以下情况时进行I/O:遇到一个换行符,进程调用fflush或进程调用exit终止。
  3. 不缓冲意味着每次调用标准I/O输出函数时都进行I/O

大多数Unix中标准I/O库的实现遵循了以下规则:

  1. 标准错误输出总是不缓冲。
  2. 标准输入和标准输出是全缓冲的。除非他们是一个终端设备,那样的话他们是行缓冲。
  3. 其他的流都是全缓冲的,除非他们是一个终端设备,那样的话他们是行缓冲。

既然套接口不是终端设备,上面str_echo函数的问题就在于输出流(fpout)是全缓冲的。
有两种解决方法:调用setvbuf将输出流强制成行缓冲的,或者在每次fputs之后调用fflush强制输出回射行。

你可能感兴趣的:(UNPv1第十三章:高级IO)