打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
UNIX网络编程读书笔记:recvmsg和sendmsg函数
userphoto

2016.11.04

关注
这两个函数是最通用的I/O函数。实际上我们可以把所有read、readv、recv和recvfrom调用替换成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() */};
这里给出的msghdr结构符合POSIX规范。有些系统仍然使用本结构源自4.2BSD的较旧版本。这个较旧的结构没有msg_flags成员,而且msg_control和msg_controllen成员分别被称为msg_accrights和msg_accrightslen。这个较旧结构唯一支持的辅助数据形式用于传递文件描述字(称为访问权限)。
msg_name和msg_namelen这两个成员用于套接口未连接的场合(譬如未连接UDP套接口)。它们类似reacvfrom和sendto的第5和第6个参数:msg_name指向一个套接口地址结构,调用者在其中存放接收者(对于sendmsg调用)或发送者(对于recvmsg调用)的协议地址。如果无需指明协议地址(例如对于TCP套接口或已连接UDP套接口),msg_name应置为空指针。msg_namelen对于sendmsg是一个值参数,对于recvmsg却是一个值-结果参数。
msg_iov和msg_iovlen这两个成员指定输入或输出缓冲区数组(即iovec结构数组),类似readv和writev的第2和第3个参数。
msg_control和msg_controllen这两个成员指定可选的辅助数据的位置和大小。
对于recvmsg和sendmsg,我们必须区别它们的两个标志变量:一个是传递值的flags参数,另一个是所传递msghdr结构的msg_flags成员,它传递的是引用,因为传递给函数的是该结构的地址。
只有recvmsg使用msg_flags成员。recvmsg被调用时,flags参数被拷贝到msg_flags成员,并由内核使用其值驱动接收处理过程。内核还依据recvmsg的结构更新msg_flags成员的值。
sendmsg忽略msg_flags成员,因为它直接使用flags参数驱动发送处理过程。这一点意味着如果想在某个sendmsg调用中设置MSG_DONTWAIT标志,那就把flags参数设置为该值;把msg_flags成员设置为该值不起作用。
如下图所示,汇总了内核为相关输入和输出函数检查的flags参数值以及recvmsg可能返回的msg_flags成员值。其中没有sendmsg msg_flags一栏,因为本组合无效。
标志 内核检查:
send flags
sendto flags
sendmsg flags 内核检查:
recv flags
recvfrom flags
recvmsg flags 内核返回:
recvmsg msg_flags
MSG_DONTROUTE
MSG_DONTWAIT
MSG_PEEK
MSG_WAITALL         
MSG_EOR
MSG_OOB         
             
MSG_BCAST
MSG_MCAST
MSG_TRUNC
MSG_CTRUNC
MSG_NOTIFICATION                  
这些标志中,内核只检查而不返回前4个标志;既检查又返回下2个标志;不检查而只返回后5个标志。recvmsg返回的7个标志解释如下:
MSG_BCAST    本标志随BSD/OS引入,相对较新。它的返回条件是:本数据报作为链路层广播收取或者其宿IP地址是一个广播地址。
MSG_MCAST    本标志随BSD/OS引入,相对较新。它的返回条件是:本数据报作为链路层多播收取。
MSG_TRUNC    本标志的返回条件是:本数据报被截断;也就是说,内核预备返回的数据超过进程事先分配的空间(所有iov_len成员之和)。
MSG_CTRUNC  本标志的返回条件是:本数据报的辅助数据被截断;也就是说,内核预备返回的辅助数据超过进程事先分配的空间(msg_controllen)。
MSG_EOR        如果返回的数据不是一个逻辑记录的结尾所在,本标志将清零;否则本标志将设置。TCP不使用本标志,因为它是一个字节流协议。
MSG_OOB       本标志绝不为TCP带外数据返回。它用于其他协议族(例如OSI协议族)。
MSG_NOTIFICATION    本标志的返回条件是:SCTP接收端读入的本消息是一个事件通知,而不是一个数据消息。
如下图所示,展示了一个msghdr结构以及它指向的各种信息。图中假设进程即将对一个UDP套接口调用recvmsg。
图中给协议地址分配了16个字节,给辅助数据分配了20个字节。为缓冲数据初始化了3个iovec结构构成的数组:第一个指定一个100字节的缓冲区,第二个指定一个60字节的缓冲区,第三个指定一个80字节的缓冲区。我们还假设已为这个套接口设置了IP_RECVDSTADDR套接口选项,以接收所读取UDP数报的宿IP地址。
我们接着假设从192.6.38.100端口2000到达一个170字节的UDP数据报,它的目的地是我们的UDP套接口,宿IP地址为206.168.112.96。如下图所示,展示了recvmsg返回时msghdr结构中的所有信息。(图中被修改过的字段标了阴影)
如下图所示为5组I/O函数之间的差异:
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
socket的read和recv函数的区别
API函数有send,sendto和sendmsg
进程间传递文件描述符 - UNIX
Netlink编程-数据结构
深入分析原始套接口
深入理解高性能网络开发路上的绊脚石 - 同步阻塞网络 IO
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服