我试图通过两个进程和Linux内核之间的共享内存区域在两个进程之间传递套接字描述符,我的目标是使用一个进程打开一个TCP套接字并使用第二个进程在同一个套接字内写入。这两个过程之间没有插座管道可能吗?
套接字描述符是int
,如何在Linux中获取描述符的本机形式?如果我只是将原生形式的描述符从进程传递给其他,我可以将数据写入打开的TCP套接字。
答案 0 :(得分:3)
不,你不能只使用一些替代方法来转移那些已进入sendmsg
电话的“东西”。当您“传递文件描述符”时,您实际传输的是访问内核内部文件对象。
cmsg结构只是一种格式化内核请求的方式,在其中你说“我想复制这个打开的文件对象,并允许读取此套接字的进程获得对它的访问”。名称SCM_RIGHTS
是一个线索,表明您传输的内容实质上是权限。
由于请求是为了操纵具有安全隐患的内核内部对象,因此您无法绕过它。你必须做一个系统调用。 sendmsg
就是这样。 (还有其他的fd传递API ......我认为在SysV上有一些关于Streams的东西。我不知道在任何最近的操作系统中是否仍然存在。至少对于BSD和Linux,sendmsg
和{ {1}}是要走的路。)
一般来说,这正是msg和cmsg之间的区别:cmsg用于内核不仅仅是将一些字节从套接字的一端复制到另一端的操作。
答案 1 :(得分:0)
使用unix socket
发送文件描述符static int
send_file_descriptor(
int socket, /* Socket through which the file descriptor is passed */
int fd_to_send) /* File descriptor to be passed, could be another socket */
{
struct msghdr message;
struct iovec iov[1];
struct cmsghdr *control_message = NULL;
char ctrl_buf[CMSG_SPACE(sizeof(int))];
char data[1];
memset(&message, 0, sizeof(struct msghdr));
memset(ctrl_buf, 0, CMSG_SPACE(sizeof(int)));
/* We are passing at least one byte of data so that recvmsg() will not return 0 */
data[0] = ' ';
iov[0].iov_base = data;
iov[0].iov_len = sizeof(data);
message.msg_name = NULL;
message.msg_namelen = 0;
message.msg_iov = iov;
message.msg_iovlen = 1;
message.msg_controllen = CMSG_SPACE(sizeof(int));
message.msg_control = ctrl_buf;
control_message = CMSG_FIRSTHDR(&message);
control_message->cmsg_level = SOL_SOCKET;
control_message->cmsg_type = SCM_RIGHTS;
control_message->cmsg_len = CMSG_LEN(sizeof(int));
*((int *) CMSG_DATA(control_message)) = fd_to_send;
return sendmsg(socket, &message, 0);
}
我的意思是发出完整的消息"共享内存中的信息
答案 2 :(得分:0)
添加到上一个答案,您必须在两个进程之间建立套接字对
pid_t pid;
int streamfd[2];
int n;
int conn_fd;
char buffer; // dummy byte character received from parent
if (socketpair(AF_UNIX, SOCK_STREAM, 0, streamfd) < 0) {
return -1;
}
然后,一个进程必须发送描述符,另一个进程必须接收它。这是接收端(此代码改编自: https://www.amazon.ca/UNIX-Network-Programming-Richard-Stevens/dp/0139498761)
int receiveDescriptor(int streamPipe, int* descriptor, void* pBuffer, size_t bytes) {
struct msghdr msgInstance;
struct iovec iov[1];
int n;
// ancillary (control) data
// This is where the descriptor will be held
#ifdef MSGHDR_MSG_CONTROL
union {
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(int))];
} control_un;
struct cmsghdr* cmptr;
msgInstance.msg_control = control_un.control;
msgInstance.msg_controllen = sizeof(control_un.control);
#else
int receivedFD;
msgInstance.msg_accrights = (caddr_t)&receivedFD;
msgInstance.msg_accrightslen = sizeof(int);
#endif
msgInstance.msg_name = NULL;
msgInstance.msg_namelen = 0;
iov[0].iov_base = pBuffer;
iov[0].iov_len = bytes;
msgInstance.msg_iov = iov;
msgInstance.msg_iovlen = 1;
n = recvmsg(streamPipe, &msgInstance, 0);
if ( n <= 0) {
return n;
}
// assume descriptor will not be received
*descriptor = -1;
// get the descriptor
#ifdef MSGHDR_MSG_CONTROL
if ( (cmptr = CMSG_FIRSTHDR(&msgInstance)) != NULL) {
if (cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
if (cmptr->cmsg_level == SOL_SOCKET && cmptr->cmsg_type == SCM_RIGHTS) {
*descriptor = *((int*)CMSG_DATA(cmptr));
}
}
}
#else
if (msgInstance.msg_accrightslen == sizeof(int)) {
*descriptor = receivedFD
}
#endif
return n;
}