日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux中进程间传递文件描述符的方法

發(fā)布時(shí)間:2024/4/11 linux 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux中进程间传递文件描述符的方法 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在進(jìn)行fork調(diào)用后,由于子進(jìn)程會(huì)拷貝父進(jìn)程的資源,所以父進(jìn)程中打開的文件描述符在子進(jìn)程中仍然保持著打開,我們很容易的就將父進(jìn)程的描述符傳遞給了子進(jìn)程。但是除了這種情況下,如果想將某個(gè)父進(jìn)程在子進(jìn)程創(chuàng)建后才打開的描述符傳遞給子進(jìn)程,又或者是想將子進(jìn)程的描述符傳遞給父進(jìn)程時(shí),就遇到了問題。

在Linux中,雖然文件描述符是一個(gè)整型值,但是它的傳遞并非只是傳遞這個(gè)值而已。因?yàn)檫@個(gè)整型值其實(shí)是文件描述符表fd_array[]的下標(biāo)

由于不同進(jìn)程的文件描述符表不同,所以要傳遞一個(gè)文件描述符,就是要在接收進(jìn)程中的文件描述符表中創(chuàng)建一個(gè)新的文件描述符,并且這兩個(gè)文件描述符要指向內(nèi)核中相同的文件表項(xiàng)

如何在兩個(gè)進(jìn)程之間傳遞文件描述符呢?在Linux下,我們可以利用UNIX域socket在程序間傳遞特殊的輔助數(shù)據(jù),以實(shí)現(xiàn)文件描述符的傳遞。

這里演示的是具有親緣關(guān)系的進(jìn)程之間的傳遞(如果需要非親緣,就將管道換成socket即可),主要借助UNIX域socket中的以下三個(gè)函數(shù),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; /* 指定的內(nèi)存緩沖區(qū) */size_t msg_iovlen; /* 緩沖區(qū)的長度 */void *msg_control; /* 輔助數(shù)據(jù) */size_t msg_controllen; /* 指向cmsghdr結(jié)構(gòu),用于控制信息字節(jié)數(shù) */int msg_flags; /* 描述接收到的消息的標(biāo)志 */ };struct cmsghdr {socklen_t cmsg_len; /* 計(jì)算cmsghdr頭結(jié)構(gòu)加上附屬數(shù)據(jù)大小 */int cmsg_level; /* 發(fā)起協(xié)議 */int cmsg_type; /*協(xié)議特定類型 */ };//獲得指向與msghadr結(jié)構(gòu)關(guān)聯(lián)的第一個(gè)cmsghdr結(jié)構(gòu) struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *msgh);//計(jì)算 cmsghdr 頭結(jié)構(gòu)加上附屬數(shù)據(jù)大小,并包括對其字段和可能的結(jié)尾填充字符 size_t CMSG_SPACE(size_t length);//計(jì)算 cmsghdr 頭結(jié)構(gòu)加上附屬數(shù)據(jù)大小 size_t CMSG_LEN(size_t length);//返回一個(gè)指針和cmsghdr結(jié)構(gòu)關(guān)聯(lián)的數(shù)據(jù) unsigned char *CMSG_DATA(struct cmsghdr *cmsg);

上述函數(shù)的使用在這里就不多介紹,可以通過查詢man手冊或者閱讀相關(guān)博客來進(jìn)行了解,下面直接實(shí)現(xiàn)功能。

//發(fā)送文件描述符 void send_fd(int sock_fd, int fd) { iovec iov[1]; msghdr msg; char buff[0]; //指定緩沖區(qū)iov[0].iov_base = buff;iov[0].iov_len = 1;//通過socketpair進(jìn)行通信,不需要知道ip地址msg.msg_name = nullptr;msg.msg_namelen = 0;//指定內(nèi)存緩沖區(qū)msg.msg_iov = iov;msg.msg_iovlen = 1;//輔助數(shù)據(jù)cmsghdr cm;cm.cmsg_len = CMSG_LEN(sizeof(sock_fd)); //描述符的大小cm.cmsg_level = SOL_SOCKET; //發(fā)起協(xié)議cm.cmsg_type = SCM_RIGHTS; //協(xié)議類型*(int*)CMSG_DATA(&cm) = fd; //設(shè)置待發(fā)送描述符//設(shè)置輔助數(shù)據(jù)msg.msg_control = &cm;msg.msg_controllen = CMSG_LEN(sizeof(sock_fd));sendmsg(sock_fd, &msg, 0); //發(fā)送描述符 }//接收并返回文件描述符 int recv_fd(int sock_fd) {iovec iov[1]; msghdr msg;char buff[0]; //指定緩沖區(qū)iov[0].iov_base = buff;iov[0].iov_len = 1;//通過socketpair進(jìn)行通信,不需要知道ip地址msg.msg_name = nullptr;msg.msg_namelen = 0;//指定內(nèi)存緩沖區(qū)msg.msg_iov = iov;msg.msg_iovlen = 1;//輔助數(shù)據(jù)cmsghdr cm;//設(shè)置輔助數(shù)據(jù)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; }

下面進(jìn)行測試一下,子進(jìn)程中打開一個(gè)文件描述符,并通過socketpair發(fā)送給父進(jìn)程,來判斷是否能夠成功讀取文件描述符中的內(nèi)容

#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}; //緩沖區(qū)//創(chuàng)建socketpair管道if(socketpair(PF_UNIX, SOCK_DGRAM, 0, pipefd) < 0){cout << "socketpair." << endl;return 1;}pid_t pid = fork(); //創(chuàng)建子進(jìn)程//子進(jìn)程if(pid == 0){close(pipefd[0]); //子進(jìn)程關(guān)閉多余的管道描述符pass_fd = open("test.txt", O_RDWR, 0666);if(pass_fd <= 0){cout << "open." << endl;}send_fd(pipefd[1], pass_fd); //子進(jìn)程通過管道發(fā)送文件描述符close(pass_fd);close(pipefd[1]);exit(0);}else if(pid < 0){//子進(jìn)程創(chuàng)建失敗cout << "fork." << endl;return 1;}close(pipefd[1]); //父進(jìn)程關(guān)閉多余描述符pass_fd = recv_fd(pipefd[0]); //父進(jìn)程從管道中接收文件描述符read(pass_fd, buff, 1024); //父進(jìn)程從緩沖區(qū)中讀出數(shù)據(jù),驗(yàn)證收發(fā)描述符是否正確cout << "fd: "<< pass_fd << " recv msg : " << buff << endl;close(pass_fd);close(pipefd[0]);return 0; }

測試結(jié)果

總結(jié)

以上是生活随笔為你收集整理的Linux中进程间传递文件描述符的方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。