zoukankan      html  css  js  c++  java
  • UNIX网络编程读书笔记:recvmsg和sendmsg函数

    这两个函数是最通用的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。

    image

    图中给协议地址分配了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结构中的所有信息。(图中被修改过的字段标了阴影)

    image

    红心如下图所示为5组I/O函数之间的差异:

    image

  • 相关阅读:
    WebAPI中路由参数中包含字符-点“.”
    Web API 授权筛选器
    WebApi
    C#视频拍照、视频录制项目示例
    WPF 获取鼠标屏幕位置、窗口位置、控件位置
    C#中字符串转换为计算公式
    ffmpeg开发文档
    .net core控制台应用程序初识
    网络书籍
    ffmpeg命令参数详解
  • 原文地址:https://www.cnblogs.com/nufangrensheng/p/3607267.html
Copyright © 2011-2022 走看看