`
danier
  • 浏览: 32257 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

进程间传递文件描述符 - UNIX

阅读更多
先来两个函数: unix_send_fd 和 unix_recv_fd
int unix_send_fd(int fd, int sendfd)
{
struct msghdr msg;
struct iovec iov[1];

/*
* Adapted from: W. Richard Stevens, UNIX Network Programming, Volume 1,
* Second edition. Except that we use CMSG_LEN instead of CMSG_SPACE; the
* latter breaks on LP64 systems.
*/
#if defined(CMSG_SPACE) && !defined(NO_MSGHDR_MSG_CONTROL)
union {
struct cmsghdr just_for_alignment;
char control[CMSG_SPACE(sizeof(sendfd))];
} control_un;
struct cmsghdr *cmptr;

memset((char *) &msg, 0, sizeof(msg)); /* Fix 200512 */
msg.msg_control = control_un.control;
msg.msg_controllen = CMSG_LEN(sizeof(sendfd)); /* Fix 200506 */

cmptr = CMSG_FIRSTHDR(&msg);
cmptr->cmsg_len = CMSG_LEN(sizeof(sendfd));
cmptr->cmsg_level = SOL_SOCKET;
cmptr->cmsg_type = SCM_RIGHTS;
*(int *) CMSG_DATA(cmptr) = sendfd;
#else
msg.msg_accrights = (char *) &sendfd;
msg.msg_accrightslen = sizeof(sendfd);
#endif

msg.msg_name = 0;
msg.msg_namelen = 0;

/*
* XXX We don't want to pass any data, just a file descriptor. However,
* setting msg.msg_iov = 0 and msg.msg_iovlen = 0 causes trouble. See the
* comments in the unix_recv_fd() routine.
*/
iov->iov_base = (void *)"";
iov->iov_len = 1;
msg.msg_iov = iov;
msg.msg_iovlen = 1;

return (sendmsg(fd, &msg, 0));
}

/* unix_recv_fd - receive file descriptor */
int unix_recv_fd(int fd)
{
const char *myname = "unix_recv_fd";

struct msghdr msg;
int newfd;
struct iovec iov[1];
char buf[1];

/*
* Adapted from: W. Richard Stevens, UNIX Network Programming, Volume 1,
* Second edition. Except that we use CMSG_LEN instead of CMSG_SPACE, for
* portability to LP64 environments.
*/
#if defined(CMSG_SPACE) && !defined(NO_MSGHDR_MSG_CONTROL)
union {
struct cmsghdr just_for_alignment;
char control[CMSG_SPACE(sizeof(newfd))];
} control_un;
struct cmsghdr *cmptr;

memset((char *) &msg, 0, sizeof(msg)); /* Fix 200512 */
msg.msg_control = control_un.control;
msg.msg_controllen = CMSG_LEN(sizeof(newfd)); /* Fix 200506 */
#else
msg.msg_accrights = (char *) &newfd;
msg.msg_accrightslen = sizeof(newfd);
#endif

msg.msg_name = 0;
msg.msg_namelen = 0;

/*
* XXX We don't want to pass any data, just a file descriptor. However,
* setting msg.msg_iov = 0 and msg.msg_iovlen = 0 causes trouble: we need
* to read_wait() before we can receive the descriptor, and the code
* fails after the first descriptor when we attempt to receive a sequence
* of descriptors.
*/
iov->iov_base = buf;
iov->iov_len = sizeof(buf);
msg.msg_iov = iov;
msg.msg_iovlen = 1;

if (recvmsg(fd, &msg, 0) cmsg_len == CMSG_LEN(sizeof(newfd))) {
if (cmptr->cmsg_level != SOL_SOCKET)
printf("%s: control level %d != SOL_SOCKET",
myname, cmptr->cmsg_level);
if (cmptr->cmsg_type != SCM_RIGHTS)
printf("%s: control type %d != SCM_RIGHTS",
myname, cmptr->cmsg_type);
return (*(int *) CMSG_DATA(cmptr));
} else
return (-1);
#else
if (msg.msg_accrightslen == sizeof(newfd))
return (newfd);
else
return (-1);
#endif
}

这两个函数来自 postfix。其中NO_MSGHDR_MSG_CONTROL应该是针对Tru64平台特有的定义。我们知道UNIX的文件描述符是一个整数,这个整数是由内核维护的一个数组的下标。在进程内部,对文件描述的操作有: open,close, dup 和 dup2。dup和dup2是将文件描述符复制一份,带SOL_SOCKET的sendmsg是不是也是这样的,它又是如何在进程间复制文件描述符的呢?
先看sendmsg在Linux内核的实现:
net/socket.c: sendmsg
net/socket.c: --> sock_sendmsg
net/socket.c: --> __sock_sendmsg
--> security_socket_sendmsg
--> sock->ops->sendmsg
security_socket_sendmsg 是一个和安全相关的函数,暂时忽略。
从代码可以看出,unix_send_fd必须使用UNIX域socket,所以sock->ops->sendmsg指向unix_stream_sendmsg 函数。
net/unix/af_unix.c: unix_stream_sendmsg
include/net/scm.h: --> scm_send
net/core/scm.c: --> __scm_send
net/core/scm.c: --> scm_fp_copy
在scm_fp_copy中,内核将要发送的文件描述符对应的file引用计数加一,发送端关闭文件时并不会真正关闭文件描述符。当然,此时发送端也可一直打开该文件描述符。

从接收端看,recvmsg堆栈和sendmsg差不多,sock->ops_recvmsg指向unix_stream_recvmsg。
在unix_stream_recvmsg又调用 scm_recv --> scm_detach_fds。
在scm_detach_fds为发送时保存的文件分配一个未使用的文件描述符,并分配file结构,然后将该文件描述符保存到用户态地址中。

分享到:
评论

相关推荐

    android进程间socket传递Ashmem的文件描述符

    总结起来,Android进程间通过Socket传递Ashmem文件描述符是一种高效的数据交换策略,尤其适用于大文件的跨进程通信。这种方法利用了Linux内核的能力,避免了复制大块数据的开销,提高了系统的性能。不过,实现时需要...

    Linux进程间传递文件描术符事例代码

    其中,通过文件描述符进行进程间传递是一种高效且灵活的方法。文件描述符是Linux系统中对打开文件的一种抽象表示,每个进程都有一个文件描述符表,用于管理其打开的文件或套接字等资源。本示例代码将探讨如何在两个...

    进程间传递描述符

    其中,进程间传递描述符是高级进程间通信的一种形式,特别是在那些没有亲缘关系的进程之间。描述符在Linux中,是指向打开文件、网络套接字、管道、信号、定时器等系统资源的引用。每个进程都拥有自己独立的进程空间...

    文件描述符1

    - 父子进程关系:在父子进程间,如果父进程打开一个文件后,子进程继承了父进程的文件描述符,它们可能指向相同的文件句柄。 - 同一进程多次打开同一文件:一个进程可以多次打开同一文件,每次都会得到新的文件...

    LINUX进程间传递描述符[收集].pdf

    本文将详细讲解Linux系统下如何通过进程间传递描述符(Descriptor Passing)来实现高级IPC。首先,每个进程都有独立的地址空间,包括各自的文件描述符表,这使得直接传递描述符变得复杂。但在Linux中,有一种机制...

    LINUX进程间传递描述符.pdf

    在Linux下,进程间传递描述符是一种高级的IPC形式,它允许一个进程向另一个进程传递已经打开的文件描述符。这种方式允许进程间共享文件、管道、套接字等资源,而无需复制数据本身。 首先,理解文件描述符是操作系统...

    unix domain socket传递描述符

    在标题中提到的"Unix domain socket传递描述符"是指一种高级特性,允许通过Unix域套接字在两个进程间传递文件描述符(file descriptor)。文件描述符是操作系统用来标识打开文件或资源的唯一数字。这种传递允许一个...

    working-with-unix-processes

    文件描述符是Unix进程模型的另一重要组成部分。在Unix中,一切皆文件。文件描述符是一个用于表述指向文件的引用的抽象概念,通常是非负整数。通过系统调用如open()、read()和write(),进程可以创建、读写和关闭文件...

    经由UNIX域套接字传送文件描述符所涉及的相关知识(自己整理)

    在进程间通信(IPC)中,能够直接传输文件描述符是非常实用的功能。这种能力使得服务器进程能够执行所有与文件相关的操作,如网络名称解析、调制解调器拨号、文件锁定协商等,并最终向请求方返回一个可用于后续I/O操作...

    jnr-unixsocket:适用于Java的UNIX域套接字(AF_UNIX)

    jnr-unixsocket库还支持文件描述符传递,这是UNIX域套接字的一个强大特性。文件描述符传递允许进程之间直接交换已打开的文件、套接字或其他资源,进一步增强了IPC的能力。 此外,jnr-unixsocket库也考虑到了安全性...

    Java网络编程--Unix域协议:概述

    虽然其他IPC机制如消息队列、共享内存、命名管道等也有各自的优势,但Unix域协议的接口兼容性使其在很多场景下成为首选,尤其是在本地高速通信和需要描述符传递的场合。 网络编程API标准IEEE POSIX 1003.1g(也称为...

    UNIX网络编程卷2:进程间通信(第2版)

    9. **文件描述符(File Descriptors)**:文件描述符是UNIX系统中访问I/O资源的关键,书中会详细解释其概念、操作和传递方式。 10. **进程间通信的综合应用**:书中通过示例程序展示如何将上述多种IPC机制组合使用...

    UNIX网络编程 第2卷 进程间通信

    6. **文件描述符(File Descriptors)**:文件描述符是UNIX系统中访问I/O资源的抽象,也是进程间通信的一种手段。书中将解释如何通过文件描述符传递数据,以及FIFO(命名管道)的工作原理。 7. **有名管道(Named ...

    prentice-Hall_UNIX网络编程_第2版_第2卷_进程间通信

    9. **文件描述符的复制(Duplication of File Descriptors)**:通过dup和fork等函数,进程可以复制文件描述符,包括套接字,实现资源的共享。 10. **守护进程(Daemons)**:常驻后台运行的进程,不与终端关联,...

    UNIX网络编程 卷2:进程间通信书中源码

    8. **文件描述符(File Descriptor)**:UNIX系统中,一切皆为文件,文件描述符可以作为通信的一种手段,例如通过`sendfile()`函数。 压缩包中的`unpv22e.tar.gz`包含了书中所有示例程序的源代码,这些代码覆盖了...

    unix环境高级编程1和unix网络编程.进程间通信2.rar

    在文件系统操作方面,作者讲解了如何打开、关闭、读取和写入文件,以及如何处理文件描述符。这对于任何需要与文件系统交互的程序都是至关重要的。此外,书中还详细讨论了文件权限、链接、符号链接和文件属性,这些都...

    第5章 进程控制与进程间通信-v31

    系统数据段则包含内核为每个进程维护的信息,如页表、进程状态、优先级、当前目录、打开的文件描述符等。 在UNIX内核中,进程的控制信息被分为user结构和proc结构两部分,分别存储运行时数据和管理信息。进程的状态...

    unix进程间通信(第二版).rar

    9. **文件和文件描述符(Files and File Descriptors)**:Unix系统中的文件描述符可以被多个进程共享,从而实现简单的通信。例如,一个进程可以打开一个文件,然后通过fork()创建子进程,子进程继承父进程的文件...

Global site tag (gtag.js) - Google Analytics