如何确定 linux 控制消息中多个辅助消息的大小
How to determine size for multiple ancillary messages in linux control messages
我尝试一次通过 unix 套接字发送多个文件描述符。这对于单个套接字来说没有问题。虽然当我尝试用 CMSG_NXTHDR
附加另一个时,我得到了一个空指针,表明我的缓冲区太短了。对于一个文件描述符,我用 CMSG_SPACE
计算了缓冲区大小,我假设我只需要将它相乘。虽然这似乎还不够。
我写了一个简短的测试程序来检查这个:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
int main(int argc, char *argv[])
{
struct msghdr msg;
if(argc != 2){
return 1;
}
union {
struct cmsghdr cmsghdr;
char control[CMSG_SPACE(sizeof(int)) * atoi(argv[1])];
} cmsgu;
struct cmsghdr *cmsg;
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = 0;
msg.msg_iovlen = 0;
msg.msg_control = cmsgu.control;
msg.msg_controllen = sizeof(cmsgu.control);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
*((int *)CMSG_DATA(cmsg)) = -1;
cmsg = CMSG_NXTHDR(&msg, cmsg);
fprintf(stderr, "%p\n", cmsg);
return 0;
}
当我用 1 调用它时,它输出一个预期的空指针。尽管我的期望是,如果用 2 CMSG_NXTHDR
调用它,那么 return 将是一个有效的指针。第一个工作值是 5(所以额外的 120 个字节)。我认为 CMSG_SPACE
会解决这个问题。有没有办法去计算需要的space?或者是否有更直接的方法在单个消息中发送多个文件描述符?
参见 this question 并回答。如果您将 memset() cmsgu 设置为 0s,您的代码应该可以工作。
但是(并回答你的第二个问题),如果你想传递多个文件描述符,你可以使用包含一个整数数组的单个 cmsghdr
。修改您的示例,
int n = atoi(argv[1]);
int myfds[n]; // use this later
union {
struct cmsghdr cmsghdr; // for alignment
char control[CMSG_SPACE(sizeof(int) * n)]; // space for one message
} cmsgu;
struct cmsghdr *cmsg;
memset(&cmsgu, 0, sizeof(cmsgu)); // as noted
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = 0;
msg.msg_iovlen = 0;
msg.msg_control = cmsgu.control;
msg.msg_controllen = sizeof(cmsgu.control);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
int *fdptr = (int *) CMSG_DATA(cmsg);
memcpy(fdptr, myfds, sizeof(int) * n);
这与 cmsg(3) 手册页中的示例基本相同。
我尝试一次通过 unix 套接字发送多个文件描述符。这对于单个套接字来说没有问题。虽然当我尝试用 CMSG_NXTHDR
附加另一个时,我得到了一个空指针,表明我的缓冲区太短了。对于一个文件描述符,我用 CMSG_SPACE
计算了缓冲区大小,我假设我只需要将它相乘。虽然这似乎还不够。
我写了一个简短的测试程序来检查这个:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
int main(int argc, char *argv[])
{
struct msghdr msg;
if(argc != 2){
return 1;
}
union {
struct cmsghdr cmsghdr;
char control[CMSG_SPACE(sizeof(int)) * atoi(argv[1])];
} cmsgu;
struct cmsghdr *cmsg;
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = 0;
msg.msg_iovlen = 0;
msg.msg_control = cmsgu.control;
msg.msg_controllen = sizeof(cmsgu.control);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
*((int *)CMSG_DATA(cmsg)) = -1;
cmsg = CMSG_NXTHDR(&msg, cmsg);
fprintf(stderr, "%p\n", cmsg);
return 0;
}
当我用 1 调用它时,它输出一个预期的空指针。尽管我的期望是,如果用 2 CMSG_NXTHDR
调用它,那么 return 将是一个有效的指针。第一个工作值是 5(所以额外的 120 个字节)。我认为 CMSG_SPACE
会解决这个问题。有没有办法去计算需要的space?或者是否有更直接的方法在单个消息中发送多个文件描述符?
参见 this question 并回答。如果您将 memset() cmsgu 设置为 0s,您的代码应该可以工作。
但是(并回答你的第二个问题),如果你想传递多个文件描述符,你可以使用包含一个整数数组的单个 cmsghdr
。修改您的示例,
int n = atoi(argv[1]);
int myfds[n]; // use this later
union {
struct cmsghdr cmsghdr; // for alignment
char control[CMSG_SPACE(sizeof(int) * n)]; // space for one message
} cmsgu;
struct cmsghdr *cmsg;
memset(&cmsgu, 0, sizeof(cmsgu)); // as noted
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = 0;
msg.msg_iovlen = 0;
msg.msg_control = cmsgu.control;
msg.msg_controllen = sizeof(cmsgu.control);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
int *fdptr = (int *) CMSG_DATA(cmsg);
memcpy(fdptr, myfds, sizeof(int) * n);
这与 cmsg(3) 手册页中的示例基本相同。