我试图了解sys/socket.h lib的msghdr结构的以下成员。

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

  • 它指出如下:



    我假设msghdr结构包含协议(protocol) header 信息?如果是,... *msg_iov是请求/响应中参数的输入/输出“vector ”吗?并且*msg_control包含响应消息?

    最佳答案

    msg_iov是长度为msg_iovlen的输入/输出缓冲区的数组。该数组的每个成员都包含一个指向数据缓冲区和缓冲区大小的指针。这就是读取/写入数据的地方。它允许您读取/写入缓冲区数组,这些缓冲区不一定位于连续的内存区域中。
    msg_control指向msg_controllen大小的缓冲区,其中包含有关数据包的其他信息。要阅读此字段,您首先需要声明一个struct cmsghdr *(我们将其称为cmhdr)。通过第一次调用CMSG_FIRSTHDR()并向其传递msghdr结构的地址,并在随后的每次传递CMSG_NXTHDR(),向其传递msghdr结构的地址和cmhdr的当前值,来填充此数据。

    msg_control中,您可以找到有趣的内容,例如数据包的目标IP(用于多播)和IP报头中的TOS/DSCP字节的内容(用于自定义拥塞控制协议(protocol))等。在大多数情况下,您需要进行setsockopt调用才能启用此数据。在给出的示例中,需要启用IP_PKTINFOIP_TOS选项。

    有关更多详细信息,请参见cmsg(3) manpage

    源IP和端口不在msg_control中,而是在msg_name中,它需要一个指向长度为struct sockaddrmsg_namelen的指针。

    这是如何使用此示例:

    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);
    }
    

    关于c - 从sys/socket.h了解msghdr结构,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32593697/

    10-10 14:42