UNIX IO 操作函数

2015-01-18 17:37:36   最后更新: 2015-01-18 17:37:36   访问数量:1735




linu 提供如下 IO 接口:

  1. read 和 write -- 最简单的读写函数
  2. readn 和 writen -- 原子性读写操作
  3. recvfrom 和 sendto -- 增加了目标地址和地址结构长度的参数
  4. recv 和 send -- 允许从进程到内核传递标志
  5. readv 和 writev -- 允许指定往其中输入数据或从其中输出数据的缓冲区
  6. recvmsg 和 sendmsg -- 结合了其他IO函数的所有特性,并具备接受和发送辅助数据的能力

 

他们之间的差异如下:

5 组 IO 函数比较
函数可用任何描述符仅套接字描述符单个读写缓冲区分散读写缓冲区可选标志可选对端地址可选控制信息
read write     
readv writev     
recv send    
recvfrom sendto   
recvmsg sendmsg  

 

前三组函数我们已经介绍过,下面对后面的三组函数进行介绍

函数原型

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);

 

定义于 sys/socket.h 中

调用成功返回输入或输出字节数,出错返回 -1

 

这两个函数与标准 read 和 write 函数的唯一差别在于增加了一个 flags 参数,当 flags 参数为 0 时,他们与标准的 read 和 write 函数

flags 参数

flags 参数可以取下列表中的一个或多个常值的逻辑或,或取 0 值

参看“recvmsg 和 sendmsg 函数”介绍中的 输入输出函数标志总结表

 

设定了 MSG_WAITALL 的 recv 函数与 readn 函数完全等价,只有当下列情况之一发生时才会返回比所请求的字节数少的数据:

  1. 被信号中断
  2. 连接被终止
  3. 套接字错误

函数原型

ssize_t readv(int filedes, const struct iovec *iov, int iovcnt); ssize_t writev(int filedes, const struct iovec *iov, int iovcnt);

 

定义于 sys/uio.h 中

调用成功返回读入或写出的字节数,否则返回-1

函数说明

这两个函数十分类似 read 和 write 函数,但是 readv 和 writev 允许单个系统调用读入或写出自一个或多个缓冲区,分别称作“分散度”和“集中写”,来自读操作的输入数据被分散到多个应用缓冲区中,同时多个应用缓冲区中的输出数据则被集中提供给单个写操作

当然,readv 和 writev 函数可以用于任何描述符,而不仅限于套接字描述符

同时,writev 是一个原子操作,这意味着对于记录的协议(如 UDP),每次 writev 操作只会生成一个数据报

参数说明

  • iovec

函数第二个参数是一个保存 iovec 结构数组的首地址的指针,iovec 结构定义在 sys/uio.h 中:

struct iovec { void *iov_base; size_t iov_len; }

 

sys/uio.h 中定义了 IOV_MAX 常量,闲置了 iovec 结构数组中元素数目的最大值

iovec 就是缓冲区结构,iov_base 保存了缓冲区首地址,而 iov_len 保存了缓冲区长度

函数原型

ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); ssize_t sendmsg(int sockfd, struct msghdr *msg, int flags);

 

定义在 sys/socket.h 中

调用成功返回输入或输出字节数,否则返回 -1

函数说明

这两个函数是最通用的 IO 函数,实际上我们可以把上述所有的 IO 操作都用这两个函数实现

参数说明

  • msg

这两个函数把大部分参数封装到了一个 msghdr 结构中:

struct msghdr { void *msg_name; // 套接字地址结构 socklen_t msg_namelen; struct iovec *msg_iov; // 缓存结构数组 int msg_iovlen; void *msg_control; // 附加数据数组 socklen_t msg_controllen; int msg_flags; // 仅供 recvmsg 函数使用,作为值-结果参数返回 }

 

msghdr 结构说明
说明
msg_name用于套接字未连接场合(如 UDP),指向一个套接字地址结构的指针,保存接收者(sendmsg)或发送者(recvmsg)的协议地址,如果无需指定协议地址(如 TCP 或已连接 UDP 套接字)则置为空指针
msg_namelenmsg_name 所指向地址结构的大小
msg_iov指向 iovec 结构数组的首地址,该数组即缓冲区数组,在 readv 和 writev 两个函数的介绍中已经介绍了该参数
msg_iovlen指定 msg_iov 数组中元素个数
msg_control可选,辅助数据数组的首地址
msg_controllenmsg_control 数组中元素个数(对于 recvmsg 函数是一个值-结果参数)
msg_flags标志变量

 

  • msg 参数的 msg_flags 和 flags 参数

我们必须区分 msghdr 结构的 msg_flags 成员和 flags 参数:

  1. 只有 recvmsg 使用 msg_flags 成员,在 recvmsg 被调用时,flags 参数被复制到 msg_flags 成员,并由内核使用其值驱动接收处理过程,并依据结果更新 msg_flags 成员
  2. sendmsg 则忽略 msg_flags 成员,因为他直接使用 flags 参数驱动发送过程

 

输入输出函数标志总结
标志说明发送函数 flags接收函数 flagsmsg_flags 返回
MSG_DONTROUTE绕过路由表查找(目的主机在某个直连的本地网络上)  
MSG_DONTWAIT仅本操作非阻塞 
MSG_PEEK窥看外来数据  
MSG_WAITALL等待所有数据(内核不在尚未读入所有请求数目字节之前让它返回)  
MSG_EOR终止记录(这通常对于SOCK_SEQPACKET套接口类型十分有用) 
MSG_OOB发送或接收带外数据
MSG_BCAST本数据报作为链路层广播接收或者其目的地址是一个广播地址  
MSG_MCAST本数据报作为链路层多播收取  
MSG_TRUNC本数据报被截断(内核预备返回的数据超过进程缓存空间)  
MSG_CTRUNC本数据报的辅助数据被截断(内核预备返回的辅助数据超过 msg_control 所能存储的大小)  
MSG_NOTIFICATION接收到的SCTP带外数据是一个事件通知而不是数据消息  

 

下图展示了 recvmsg 返回时值的例子:

 

辅助控制信息(msg_control、msg_controllen 成员)

辅助数据可以通过调用 sendmsg 和 recvmsg 这两个函数使用 msghdr 结构中的 msg_control 和 msg_controllen 成员发送和接收

msg_control 成员是下面介绍的 cmsghdr 结构的数组

 

struct cmsghdr { socklen_t cmsg_len; int cmsg_level; int cmsg_type; unsigned char cmsg_data[]; }

 

 

  • 辅助数据结构用法:
辅助数据用法
协议cmsg_levelcmsg_type说明
IPv4IPPROTO_IPIP_REVDSTADDR随 UDP 数据报接收目的地址
IP_RECVIF随 UDP 数据报接收接口索引
IPv6IPPROTO_IPV6IPV6_DSTOPTS指定/接收目的地选项
IPV6_HOPLIMIT指定/接收跳限
IPV6_HOPOPTS指定/接收步跳选项
IPV6_NEXTHOP指定下一跳的地址
IPV6_PKTINFO指定/接收分组信息
IPV6_RTHDR指定/接收路由首部
IPV6_TCLASS指定/接收分组流通类别
UNIX域SOL_SOCKETSCM_RIGHTS发送/接收描述符
SCM_CREDS发送/接收用户凭证

 

  • 辅助数据处理函数

下面列出了 5 个宏用来简化对辅助数据的处理

struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *mhdrptr); // 返回指向第一个 cmsghdr 结构的指针或为 NULL struct cmsghdr *CMSG_NXTHDR(struct msghdr *mhdrptr, struct cmsghdr *cmsgptr); // 返回指向 cmhdrptr 下一个辅助对象指针或为 NULL unsigned char *CMSG_DATA(struct cmsghdr *cmsgptr); // 返回指向 cmsghdr 结构关联的数据的第一个字节的指针 unsigned int CMSG_LEN(unsigned int length); // 返回给定数据量下存放到 cmsg_len 中的值 unsigned int CMSG_SPACE(unsigned int length); // 返回给定数据量下一个辅助数据对象总的大小

 

 






读书笔记      技术帖      linux      unix      network      c语言      unp      unix网络编程      tcp      udp      网络编程      龙潭书斋      io      read      write      sendto      recvfrom      readn      writen      readv      writev      recv      send     


京ICP备15018585号