【问题标题】:Understanding the msghdr structure from sys/socket.h从 sys/socket.h 了解 msghdr 结构
【发布时间】:2015-12-12 03:51:03
【问题描述】:

我正在尝试了解sys/socket.h 库的msghdr 结构的以下成员。

  • struct iovec *msg_iov scatter/gather array
  • void *msg_control ancillary data, see below

如下:

辅助数据由一系列对组成,每个对由一个 cmsghdr 结构和一个数据数组组成。数据数组包含辅助数据消息,cmsghdr 结构包含允许应用程序正确解析数据的描述性信息。


我假设 msghdr 结构包含协议头信息?如果是这样...*msg_iov 是请求/响应中参数的输入/输出“向量”吗? *msg_control 包含响应消息?

【问题讨论】:

    标签: c linux sockets network-programming


    【解决方案1】:

    msg_iov 是长度为msg_iovlen 的输入/输出缓冲区数组。该数组的每个成员都包含一个指向数据缓冲区的指针和缓冲区的大小。这是要读取/写入的数据所在的位置。它允许您读取/写入不一定在连续内存区域中的缓冲区数组。

    msg_control 指向大小为msg_controllen 的缓冲区,其中包含有关数据包的附加信息。要读取这个字段,首先需要声明一个struct cmsghdr *(我们称之为cmhdr)。您可以通过第一次调用CMSG_FIRSTHDR() 来填充它,将msghdr 结构的地址传递给它,然后每次调用CMSG_NXTHDR(),将msghdr 结构的地址和cmhdr 的当前值传递给它。

    msg_control,您可以找到有趣的信息,例如数据包的目标 IP(对多播有用)和 IP 标头中 TOS/DSCP 字节的内容(对自定义拥塞控制协议有用)等.在大多数情况下,您需要拨打setsockopt 来启用接收此数据。在给出的示例中,需要启用IP_PKTINFOIP_TOS 选项。

    有关详细信息,请参阅cmsg(3) manpage

    源 IP 和端口不在 msg_control 中,但在 msg_name 中,它需要一个指向长度为 msg_namelenstruct sockaddr 的指针。

    这是一个如何使用它的示例:

    struct msghdr mhdr;
    struct iovec iov[1];
    struct cmsghdr *cmhdr;
    char control[1000];
    struct sockaddr_in sin;
    char databuf[1500];
    unsigned char tos;
    
    mhdr.msg_name = &sin
    mhdr.msg_namelen = sizeof(sin);
    mhdr.msg_iov = iov;
    mhdr.msg_iovlen = 1;
    mhdr.msg_control = &control;
    mhdr.msg_controllen = sizeof(control);
    iov[0].iov_base = databuf;
    iov[0].iov_len = sizeof(databuf);
    memset(databuf, 0, sizeof(databuf));
    if ((*len = recvmsg(sock, &mhdr, 0)) == -1) {
        perror("error on recvmsg");
        exit(1);
    } else {
        cmhdr = CMSG_FIRSTHDR(&mhdr);
        while (cmhdr) {
            if (cmhdr->cmsg_level == IPPROTO_IP && cmhdr->cmsg_type == IP_TOS) {
                // read the TOS byte in the IP header
                tos = ((unsigned char *)CMSG_DATA(cmhdr))[0];
            }
            cmhdr = CMSG_NXTHDR(&mhdr, cmhdr);
        }
        printf("data read: %s, tos byte = %02X\n", databuf, tos); 
    }
    

    【讨论】:

    • 为什么是struct sockaddr_in?不应该是struct sockaddr吗?
    • struct sockaddr 是获取套接字信息的通用类型。对于 IPv4 套接字,特定类型是 struct sockaddr_in。对于 UNIX 域套接字,它是 struct sockaddr_un,对于 IPv6 套接字,它是 struct sockaddr_in6
    • 哈哈好吧。哈哈,你到底在哪里看到的?我什至在规范中都没有看到。
    • man 7 ipman 7 unixman 7 ipv6,以及man 7 socket
    • 好吧,现在明白了……他们真的应该把这些东西放在主要规范中,或者至少把它放在 cmets 中,而不是声明一个泛型类型,因为你甚至不能使用那个泛型类型对吧?
    猜你喜欢
    • 1970-01-01
    • 2023-03-22
    • 2015-12-21
    • 1970-01-01
    • 2021-08-15
    • 2011-02-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多