Linux中进程间传递文件描述符的方法
在进行fork调用后,由于子进程会拷贝父进程的资源,所以父进程中打开的文件描述符在子进程中仍然保持着打开,我们很容易的就将父进程的描述符传递给了子进程。但是除了这种情况下,如果想将某个父进程在子进程创建后才打开的描述符传递给子进程,又或者是想将子进程的描述符传递给父进程时,就遇到了问题。
在Linux中,虽然文件描述符是一个整型值,但是它的传递并非只是传递这个值而已。因为这个整型值其实是文件描述符表fd_array[]的下标
由于不同进程的文件描述符表不同,所以要传递一个文件描述符,就是要在接收进程中的文件描述符表中创建一个新的文件描述符,并且这两个文件描述符要指向内核中相同的文件表项。
如何在两个进程之间传递文件描述符呢?在Linux下,我们可以利用UNIX域socket在程序间传递特殊的辅助数据,以实现文件描述符的传递。
这里演示的是具有亲缘关系的进程之间的传递(如果需要非亲缘,就将管道换成socket即可),主要借助UNIX域socket中的以下三个函数,socketpair、sendmsg、recvmsg
int socketpair(int domain, int type, int protocol, int sv[2]);
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);struct msghdr
{void *msg_name; /* 目的IP地址 */socklen_t msg_namelen; /* 地址长度 */struct iovec *msg_iov; /* 指定的内存缓冲区 */size_t msg_iovlen; /* 缓冲区的长度 */void *msg_control; /* 辅助数据 */size_t msg_controllen; /* 指向cmsghdr结构,用于控制信息字节数 */int msg_flags; /* 描述接收到的消息的标志 */
};struct cmsghdr {socklen_t cmsg_len; /* 计算cmsghdr头结构加上附属数据大小 */int cmsg_level; /* 发起协议 */int cmsg_type; /*协议特定类型 */
};//获得指向与msghadr结构关联的第一个cmsghdr结构
struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *msgh);//计算 cmsghdr 头结构加上附属数据大小,并包括对其字段和可能的结尾填充字符
size_t CMSG_SPACE(size_t length);//计算 cmsghdr 头结构加上附属数据大小
size_t CMSG_LEN(size_t length);//返回一个指针和cmsghdr结构关联的数据
unsigned char *CMSG_DATA(struct cmsghdr *cmsg);
上述函数的使用在这里就不多介绍,可以通过查询man手册或者阅读相关博客来进行了解,下面直接实现功能。
//发送文件描述符
void send_fd(int sock_fd, int fd)
{ iovec iov[1]; msghdr msg; char buff[0]; //指定缓冲区iov[0].iov_base = buff;iov[0].iov_len = 1;//通过socketpair进行通信,不需要知道ip地址msg.msg_name = nullptr;msg.msg_namelen = 0;//指定内存缓冲区msg.msg_iov = iov;msg.msg_iovlen = 1;//辅助数据cmsghdr cm;cm.cmsg_len = CMSG_LEN(sizeof(sock_fd)); //描述符的大小cm.cmsg_level = SOL_SOCKET; //发起协议cm.cmsg_type = SCM_RIGHTS; //协议类型*(int*)CMSG_DATA(&cm) = fd; //设置待发送描述符//设置辅助数据msg.msg_control = &cm;msg.msg_controllen = CMSG_LEN(sizeof(sock_fd));sendmsg(sock_fd, &msg, 0); //发送描述符
}//接收并返回文件描述符
int recv_fd(int sock_fd)
{iovec iov[1]; msghdr msg;char buff[0]; //指定缓冲区iov[0].iov_base = buff;iov[0].iov_len = 1;//通过socketpair进行通信,不需要知道ip地址msg.msg_name = nullptr;msg.msg_namelen = 0;//指定内存缓冲区msg.msg_iov = iov;msg.msg_iovlen = 1;//辅助数据cmsghdr cm;//设置辅助数据msg.msg_control = &cm;msg.msg_controllen = CMSG_LEN(sizeof(sock_fd));recvmsg(sock_fd, &msg, 0); //接收文件描述符int fd = *(int*)CMSG_DATA(&cm);return fd;
}
下面进行测试一下,子进程中打开一个文件描述符,并通过socketpair发送给父进程,来判断是否能够成功读取文件描述符中的内容
#include <sys/socket.h>
#include<sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>#include <iostream>
using std::cout;
using std::endl;int main()
{int pipefd[2]; //管道int pass_fd = 0; //待传送描述符char buff[1024] = {0}; //缓冲区//创建socketpair管道if(socketpair(PF_UNIX, SOCK_DGRAM, 0, pipefd) < 0){cout << "socketpair." << endl;return 1;}pid_t pid = fork(); //创建子进程//子进程if(pid == 0){close(pipefd[0]); //子进程关闭多余的管道描述符pass_fd = open("test.txt", O_RDWR, 0666);if(pass_fd <= 0){cout << "open." << endl;}send_fd(pipefd[1], pass_fd); //子进程通过管道发送文件描述符close(pass_fd);close(pipefd[1]);exit(0);}else if(pid < 0){//子进程创建失败cout << "fork." << endl;return 1;}close(pipefd[1]); //父进程关闭多余描述符pass_fd = recv_fd(pipefd[0]); //父进程从管道中接收文件描述符read(pass_fd, buff, 1024); //父进程从缓冲区中读出数据,验证收发描述符是否正确cout << "fd: "<< pass_fd << " recv msg : " << buff << endl;close(pass_fd);close(pipefd[0]);return 0;
}
测试结果
Linux中进程间传递文件描述符的方法相关推荐
- Linux高级进程编程———在任意两个进程间传递文件描述符:使用 sendmsg 和 recvmsg 实现
进程间传递打开的文件描述符,并不是传递文件描述符的值.那么在传递时究竟传递了什么?我们要先搞明白这个问题. 1.文件描述符 文件描述符的值与文件没有任何联系,只是该文件在进程中的一个标识,所以同一文件 ...
- Linux 进程间传递文件描述符
文章目录 文件描述符 文件数据结构 共享文件 UNIX域socket实现传递文件描述符 进程间传递打开的文件描述符,并不是传递文件描述符的值.先说一下文件描述符. 文件描述符 对内核来说,所有打开的文 ...
- 进程间传递文件描述符--sendmsg,recvmsg(可用)
UNIX域套接字可以在同一台主机上各进程之间传递文件描述符. 下面先来看两个函数: #include <sys/types.h> #include <sys/socket.h> ...
- android进程间传递文件描述符原理
在Linux中,进程打开一个文件,返回一个整数的文件描述符,然后就可以在这个文件描述符上对该文件进行操作.那么文件描述符和文件到底是什么关系?进程使用的是虚拟地址,不同进程间是地址隔离的,如何在两个进 ...
- Linux的辅助数据和传递文件描述符
简介 首先,明确传递文件描述符的意义.一般来说,在多进程网络编程中,我们设置一个主进程用于监听新来的连接,设置一个进程池,用于处理这些连接.但是,与线程池不同,进程池各个进程之间的空间是独立的,直接共 ...
- 不相干进程之间传递文件描述符
#include <sys/socket.h> #include <fcntl.h> #include <stdio.h> #include <unistd. ...
- Linux系统学习笔记:文件描述符标志
文件描述符标志的概念 文件描述符标志(目前就只有一个close-on-exec): 它仅仅是一个标志,当进程fork一个子进程的时候,在子进程中调用了exec函数时就用到了这个标志.意义是执行exec ...
- 线程共享的环境包括:进程代码段、进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯)、进程打开的文件描述符、信号的处理器、进程的当前目录和进程用户ID与进程组ID。 进程拥有这
线程共享的环境: 进程代码段.进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯).进程打开的文件描述符.信号的处理器.进程的当前目录和进程用户ID与进程组ID. 进程拥有这许多共性的 ...
- linux dup用法,Linux:dup和dup2文件描述符及函数解析,dupdup2
Linux:dup和dup2文件描述符及函数解析,dupdup2 一.文件描述符 1.1 文件描述符概念 我们知道在Linux下一切皆文件,因此我们需要一个东西对这些文件进行管理,此时就需要文件描述符 ...
最新文章
- a10双核(8dm1)-android4.1.1-v2.07,台电官方论坛 - A10 双核 8DM1 2G ROM 4.0.4 固件 - 平板笔记本...
- 只需1秒,无人机就能平地翻跟头 | IEEE
- Android Camera架构分析
- CAN 总线 之四 BOSCH CAN2.0 Part A
- 【计算机系统结构】第一周 课上笔记
- CCF201312-3 最大的矩形(100分)
- 前端学习(1984)vue之电商管理系统电商系统之完成静态属性
- 利用VS2012自带功能,将xml文档反序列化为对象
- zeromq不需要消息服务器,ZeroMQ发布订阅TCP丢弃消息订阅服务器失败
- 剑指offer 面试题5—从尾到头打印链表
- 20年未解的MIT密码难题,被自学成才的程序员破解了,比预计早15年
- 中国无人车第一案!百度状告景驰王劲:窃取机密,不还电脑,索赔5000万
- hadoop安装和基本知识
- 基于Go的马蜂窝旅游网分布式IM系统技术实践
- python简单的构建爬虫ip代理池
- 什么是王道?什么是王道中的王道?
- c语言工具栏运行不见了,电脑下面的任务栏不见了怎么办 几种方法介绍
- CyclicBarrier栅栏
- 双代号网络图如何用计算机画,怎么画双代号网络图,双代号网络图的绘制规则和步骤...
- To install spack and your first package
热门文章
- log4j2.xml
- webclientt和httpwebrequest
- Shiro使用redis作为缓存(解决shiro频繁访问Redis)
- 大数据构建模块:选择体系结构和开源框架
- OkHttp如何移除User-Agent,Accept-Encoding等框架自动添加的请求头参数
- Java中String、StringBuffer、StringBuilder的区别
- 设计原则--开放-封闭原则(OCP)
- Linux命令行上执行操作,不退回命令行的解决方法
- 汇编实现大写转小写函数(to_lower)
- WP7 开发(九) WP7控件开发(六)-DeepZoom技术