zoukankan      html  css  js  c++  java
  • sendmsg 和 recvmsg 函数

    1. 基础介绍

      最通用的I/O函数,只要设置好参数,read、readv、recv、recvfrom和write、writev、send、sendto等函数都可以对应换成这两个函数来调用。同时,各种输出函数调用也可以替换成sendmsg调用。

    #include <sys/socket.h>
    ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
    ssizt_t sendmsg(int sockfd, struct msghdr *msg, int flags);

    大部分参数都在 msghdr结构中

    struct iovec
    {                   /* Scatter/gather array items */
        void *iov_base; /* Starting address */
        size_t iov_len; /* Number of bytes to transfer */
    };
    
    struct msghdr
    {
        void *msg_name;        /* optional address */
        socklen_t msg_namelen; /* size of address */
        struct iovec *msg_iov; /* scatter/gather array */
        size_t msg_iovlen;   /* # elements in msg_iov */
        void *msg_control;   /* ancillary data, see below */
        size_t msg_controllen; /* ancillary data buffer len */
        int msg_flags;         /* flags on received message */
    };

    struct msghdr 结构体参数说明:

    • msg_name : 指向一个套接字地址结构,用于存放接受者或者发送者的协议地址。无需指明时,置为空 。
    • msg_iov,msg_iovlen : 指定输入或输出的缓冲区数组。
    • msg_control,msg_controllen : 可选的辅助数据的位置和大小。

    注意事项:

    1. sendmsg中,会忽略msg_flags成员,他会按照参数flags直接处理。那么当我们去设置MSG_DONTWAIT(临时非阻塞)是就把flags设为MSG_DONTWAIT而把msg_flags设为不起作用。
    2. recvmsg中,使用msg_flags参数,他会将flags复制到msg_flags中进行处理。另外内核还可能将msg_flags的值更改。(因为在调用这两个函数的时候,第二个参数都是通过指针去调用的)

    2. 图解其结构

    这里写图片描述

      协议地址16字节,辅助数据20字节。然后 iovec() 是三个缓冲数据数组。

    这里写图片描述

    • msg_name :填充了一个套接字地址结构。包括:源ip和端口
    • msg_namelen :因为调用前和调用后之没有发生改变,所以还是返回 16
    • msg_control:填充了一个cmsghdr()结构
    • msg_controllen:,返回实际填入的字节数—>16
    • msg_flags:也会被内核更新,但是在这里没有标志返回给进程

       5组I/O函数的比较
    这里写图片描述

    3. 辅助数据

    辅助数据又叫作控制信息,通过msg_controlmsg_controllen来实现发送和接受。辅助数据的用途主要有:

    这里写图片描述

    它由一个或者多个辅助对象构成。对象由头部和身体组成 。头部是struct cmsghdr结构,身体是实际数据。 类似于http报文的结构。可以在头部与身体之间有填充字节,也可以在身体与下一个对象之间有填充字节。见下图 :

    struct cmsghdr {
         size_t cmsg_len;    /* Data byte count, including header
                                 (type is socklen_t in POSIX) */
          int    cmsg_level;  /* Originating protocol */
          int    cmsg_type;   /* Protocol-specific type */
      /* followed by
          unsigned char cmsg_data[]; */
       };
    

    注意事项: 由msg_control指向的辅助数据必须为cmsghdr结构适当的对齐。

       以下是在一个控制缓冲区中出现2个辅助数据对象的例子:

    这里写图片描述

    以下是通过一个unix域套接字传递描述符 或者传递凭证时所用的cmsghdr结构:

    这里写图片描述

    疑问:那么假如对端传递过来了一个描述符的话,那我如何能够获取到该辅助数据呐?自己手动分配空间给cmsg_data[]吗?当然不是,这些系统已经帮我们想好了。系统提供了以下的5个宏来实现。

    #include <sys/socket.h>
    #include <sys/param.h>
    struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *mhdrptr);
        //返回:指向第一个cmsghdr结构的指针,若无辅助数据则为NULL
    struct cmsghdr *CMSG_NXTHDR(struct msghdr *mhdrptr, struct cmsghdr *cmsghdr);
        //返回:指向下一个cmsghdr结构的指针,若不再有辅助数据对象则为NULL
    unsigned char *CMSG_DATA(struct cmsghdr *cmsgptr);
        //返回:指向与cmsghdr结构关联的数据的第一个字节的指针
    unsigned char *CMSG_LEN(unsigned int length);
        //返回:给定数据量下存放到cmsg_len中的值
    unsigned char *CMSG_SPACE(unsigned int length);
        //返回:给定数据量下一个辅助数据对象总的大小。

    那么就可以进行如下调用啦!!

    struct msghdr msg;
    struct cmsghdr *cmsgptr;
    for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
         cmsgptr = CMSG_NXTHDR(&msg, cmsgptr))
    {
        /* 判断是否自己需要 msg_level和msg_type */
        u_char *ptr;
        ptr = CMSG_DATA(cmsgptr); /* 获取辅助数据 */
        /*通过ptr处理身体部分*/
    }

    注意事项: CMSG_LEN不计身体与下一个对象之间的填充字节,CMSG_SPACE反之。

    实例1 :使用sendmsgrecvmsg在进程之间传递描述符,见下一篇博客.

    附录:(1)recvfrom && sendto 函数

     #include <sys/types.h>
     #include <sys/socket.h>
    
    ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                          const struct sockaddr *dest_addr, socklen_t addrlen);
    
    ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                            struct sockaddr *src_addr, socklen_t *addrlen);
    

      通常在UDP中使用,当然也可以用于TCP!因为UDP是无连接的,所以每次发送和接受时需要指明(IP地址和端口号)。

  • 相关阅读:
    C++之容器
    C++之复制控制
    TCP的3次握手/4次握手
    linux编程之多线程编程
    linux编程之信号
    linux编程之共享内存
    MySQL数据库优化
    MySQL存储引擎InnoDB与Myisam
    Redis--持久化
    Redis 请求应答模式和往返延时 Pipelining
  • 原文地址:https://www.cnblogs.com/Tattoo-Welkin/p/10335261.html
Copyright © 2011-2022 走看看