我试图理解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
包含响应消息?
答案 0 :(得分: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_PKTINFO
和IP_TOS
选项。
有关详细信息,请参阅cmsg(3) manpage。
源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);
}