c - 在从 Linux 套接字发送/接收数据包后访问辅助数据时,在哪些情况下 msg_controllen 可以为 0?
问题描述
我正在开发一个非常复杂的 C 程序,旨在在 Linux 下运行,它在很大程度上依赖于来自套接字的辅助数据。
我实际上遇到了一种奇怪的行为,顺便说一句,这似乎只发生在我的程序上(其他示例代码,比如这个,工作正常)。我通过定义使用辅助数据:
struct msghdr mhdr;
struct iovec iov;
struct cmsghdr *cmsg = NULL;
struct sockaddr_ll addrll;
socklen_t addrllLen=sizeof(addrll);
unsigned char packet[PACKET_SIZE_MAX];
char ctrlBuf[CMSG_SPACE(sizeof(struct scm_timestamping))]; // For example, in order to retrieve timestamps
然后,通过设置:
memset(&mhdr,0,sizeof(mhdr));
iov.iov_base=packet;
iov.iov_len=sizeof(packet);
mhdr.msg_name=&(addrll); // This is a raw socket
mhdr.msg_namelen=addrllLen; // This is a raw socket
mhdr.msg_control=ctrlBuf;
mhdr.msg_controllen=sizeof(ctrlBuf);
mhdr.msg_iov=&iov;
mhdr.msg_iovlen=1;
mhdr.msg_flags=0;
然后,在设置一些套接字选项以检索有用的辅助数据(例如软件或硬件时间戳,通过设置)之后,我使用sendto()
and发送和接收数据。我能够验证我打开的套接字实际上支持这些选项。recvmsg()
SO_TIMESTAMPING
当我尝试使用如下代码提取辅助数据时,有时会出现问题,例如,提取struct scm_timestamping
带有发送/接收时间戳的 a:
for(cmsg=CMSG_FIRSTHDR(&mhdr);cmsg!=NULL;cmsg=CMSG_NXTHDR(&mhdr, cmsg)) {
if(cmsg->cmsg_level==SOL_SOCKET && cmsg->cmsg_type==SO_TIMESTAMPING) {
hw_ts=*((struct scm_timestamping *)CMSG_DATA(cmsg));
}
}
有时,CMSG_FIRSTHDR(&mhdr)
返回一个空指针,返回的mhdr.msg_controllen
是0
,这样我就无法提取任何时间戳。其他时候,在同一台 PC 上并使用相同的 NIC,一切都很好。
所以,我的问题是:一般情况下,在哪些情况下可以mhdr.msg_controllen
返回0
?这可能是由于定义中的问题struct msghdr
吗?还是这是由于某种内核问题?
解决方案
很可能您的控制消息缓冲区过小,因为它没有对齐并且第一个对齐边界下方的部分将无法使用。我不确定设置缓冲区的正确惯用方法是什么(可能使用malloc
是避免代码的唯一方法,严格来说,由于对齐和有效类型/“别名”违规而导致 UB),但是添加_Alignof(max_align_t)
(或sizeof(max_align_t)
) 到缓冲区大小可能是一种解决方案。不过,我想知道公认的“正确”方法是什么。
cmsg(3)
手册页似乎建议使用联合进行对齐:
union { /* Ancillary data buffer, wrapped in a union in order to ensure it is suitably aligned */ char buf[CMSG_SPACE(sizeof(myfds))]; struct cmsghdr align; } u;
推荐阅读
- arrays - 用于数据验证和 if 函数的数组公式
- r - r - ggplot - y 尺度
- sql - 如何在 Oracle SQL Developer 中生成带有子查询的 INSERT 语句?
- yaml - 如何在全球范围内向我的 aws 资源添加标签
- javascript - 问题是当我单击导航栏中的链接时,它没有转到其部分
- reactjs - 反应升级到 16 的草稿 js 问题
- javascript - Gmail 自动回复脚本 - 如何停止多次回复?
- c# - 创建新的 .NET 6 MAUI 项目
- windows - 如何解决这个 gitbash `没有这样的目录`问题?
- vue.js - 如何配置 Webpack 和 Vue-Loader 将警告视为错误?