这两个函数是最通用的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函数之间的差异:

UNIX网络编程读书笔记:recvmsg和sendmsg函数的更多相关文章

  1. UNIX网络编程读书笔记:地址操纵函数

    地址格式转换函数:它们在ASCII字符串(人们比较喜欢用的格式)与网络字节序的二进制值(此值存于套接口地址结构中)间转换地址. 1.inet_aton.inet_addr.inet_ntoa inet ...

  2. UNIX网络编程读书笔记:字节操纵函数

    #include <strings.h> void bzero(void *dest, size_t nbytes); void bcopy(const void *src, void * ...

  3. UNIX网络编程--读书笔记

    会集中这段时间写UNIX网络编程这本书的读书笔记,准备读三本,这一系类的文章会不断更新,一直会持续一个月多,每篇的前半部分是书中讲述的内容,每篇文章的后半部分是自己的心得体会,文章中的红色内容是很重要 ...

  4. UNIX网络编程读书笔记:简介

    认知套接口编程接口 理解原始套接口(raw socket)的概念   值得注意的是,客户和服务器是典型的用户进程,而TCP和IP协议则通常是系统内核协议栈的一部分. 上图中在TCP和UDP之间留有间隙 ...

  5. UNIX网络编程读书笔记:原始套接口

    概述 应用程序可以绕过传输层而直接使用IPv4和IPv6,这称为原始套接口(raw socket).http://www.cnblogs.com/nufangrensheng/p/3583435.ht ...

  6. UNIX网络编程读书笔记:基本SCTP套接口编程

    概述 SCTP是一个较新的传输协议,于2000年在IETF得到标准化(TCP是在1981年标准化的).它最初是为满足不断增长的IP电话市场设计的:具体地说,就是穿越因特网传输电话信令. SCTP是一个 ...

  7. Unix 网络编程 读书笔记1

    第一章: C/C++语言提供两种不同的编程模式:IPL32和PL64.► IPL32 ● 表示integer/pointer/long三种数据类型是32位(4个字节),在这种模式下,提供32位的地址空 ...

  8. UNIX网络编程读书笔记:套接口选项

    概述 有很多方法来获取和设置影响套接口的选项: getsockopt和setsockopt函数 fcntl函数 ioctl函数 getsockopt和setsockopt函数 这两个函数仅用于套接口. ...

  9. UNIX网络编程读书笔记:UNIX域协议

    概述 UNIX域协议并不是一个实际的协议族,而是在单个主机上执行客户/服务器通信的一种方法,所用API与在不同主机上执行客户/服务器通信所用的API(套接口API)相同.UNIX域协议可视为进程间通信 ...

随机推荐

  1. 51nod1981 如何愉快地与STL玩耍

    先摆官方题解吧......... ....................有什么好讲的呢....... 注意一些地方常数优化一下.......然后......$bitset$怎么暴力怎么来吧..... ...

  2. Pollard-rho算法:模板

    #include<algorithm> #include<cstdio> #include<cstdlib> #define N 5500 using namesp ...

  3. MySql默认编码所造成的乱码麻烦1.222

    1.前言 MySQL在安装时,最后的一步,会让你选择MySQL服务器及客户端.数据库.连接接口的默认编码.通常可选择 UTF8和GB2312. 但是,如果你选择了utf8的时候,恰好你要从另一个数据库 ...

  4. cordova安卓手机<a href="tel:xxx"></a>无法进入拨号界面问题

    在使用cordova开发跨平台APP时,可能会用到点击某个按钮进入拨号界面的问题,HTML中的a标签提供了这个功能,但在部分安卓手机中却没有作用,点击没有反应,解决的方法如下:(在config.xml ...

  5. 九月回顾 这篇文章和ACM毫无关系= =

    其实不只是九月的回顾吧,我大概想把暑假到现在10.01发生的啥事儿都说下吧~ 嗯,我是一个比较沙茶的人,不过运气比较好吧. 高中啊,这个谈起来话就长了,在校什么风采之星大赛上,我认识了个妹子,当时感觉 ...

  6. 对于GTPv1协议头部的解析

    参考ETSI EN 301 347 GTP是GPRS Tunnelling Protocol 的简称.GTP分为GTPv0(已经淘汰),GTPv1 和GTPv2.下面,介绍的是GTPv1. GTPv1 ...

  7. Debounce 和 Throttle 的原理及实现---防止频繁触发某事件

    原文:http://blog.csdn.net/redtopic/article/details/69396722 在处理诸如 resize.scroll.mousemove 和 keydown/ke ...

  8. 将DLL挂接到远程进程之中(远程注入)

    线程的远程注入 要实现线程的远程注入必须使用Windows提供的CreateRemoteThread函数来创建一个远程线程该函数的原型如下:HANDLE CreateRemoteThread(    ...

  9. Using an open debug interconnect model to simplify embedded systems design

    Using an open debug interconnect model to simplify embedded systems design Tom Cunningham, Freescale ...

  10. C#:让您知道您的方法是被何“人”调用

    我们要在DisabledObsoleteMethod函数里限制具有“Obsolete”属性的方法调用,我们如何去做呢?在.Net中提供了一个"StackFrame"类用于表示当前线 ...