从sys/socket.h了解msghdr结构

Jor*_*vis 6 c sockets linux network-programming

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

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

它在下面说明:

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


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

dbu*_*ush 6

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)联机帮助页.

源IP和端口不在msg_control,但在msg_name其中需要指向struct sockaddr具有长度的指针msg_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); 
}
Run Code Online (Sandbox Code Playgroud)

  • `struct sockaddr` 是一种用于获取套接字信息的通用类型。对于 IPv4 套接字,特定类型是 `struct sockaddr_in`。对于 UNIX 域套接字,它是 `struct sockaddr_un`,对于 IPv6 套接字,它是 `struct sockaddr_in6` (2认同)