进程间传递文件描述符--sendmsg,recvmsg

从 msghdr 结构体到 SCM_RIGHTS:深入解析 recvmsg/sendmsg 在进程间传递文件描述符的完整流程 本文深入解析了Linux系统中通过recvmsg/sendmsg和SCM_RIGHTS实现进程间文件描述符传递的完整流程。从msghdr结构体的详细解读到内核实现原理,全面介绍了这一高效进程间通信技术的核心机制、实战技巧和安全实践,帮助开发者掌握这一高级IPC技术。 阅读详情

UNIX域套接字可以在同一台主机上各进程之间传递文件描述符。

下面先来看两个函数:

[cpp]  view plain  copy
  1. #include <sys/types.h>   
  2. #include <sys/socket.h>   
  3.   
  4. ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);   
  5. ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);  

它们与sendto 和 recvfrom 函数相似,只不过可以传输更复杂的数据结构,不仅可以传输一般数据,还可以传输额外的数据,即文件描述符。下面来看结构体msghdr :

[cpp]  view plain  copy
  1. struct msghdr {   
  2.     void         *msg_name;       /* optional address */   
  3.     socklen_t     msg_namelen;    /* size of address */   
  4.     struct iovec *msg_iov;        /* scatter/gather array */   
  5.     size_t        msg_iovlen;     /* # elements in msg_iov */   
  6.     void         *msg_control;    /* ancillary data, see below */   
  7.     size_t        msg_controllen; /* ancillary data buffer len */   
  8.     int           msg_flags;      /* flags on received message */   
  9. };   

1、msg_name :即对等方的地址指针,不关心时设为NULL即可;

2、msg_namelen:地址长度,不关心时设置为0即可;

3、msg_iov:是结构体iovec 的指针。   

[cpp]  view plain  copy
  1. struct iovec {   
  2.                void  *iov_base;    /* Starting address */   
  3.                size_t iov_len;     /* Number of bytes to transfer */   
  4.            };  

成员iov_base 可以认为是传输正常数据时的buf,iov_len 是buf 的大小。

4、msg_iovlen:当有n个iovec 结构体时,此值为n;

5、msg_control:是一个指向cmsghdr 结构体的指针

[cpp]  view plain  copy
  1. struct cmsghdr {   
  2.           socklen_t cmsg_len;    /* data byte count, including header */   
  3.           int       cmsg_level;  /* originating protocol */   
  4.           int       cmsg_type;   /* protocol-specific type */   
  5.           /* followed by unsigned char cmsg_data[]; */   
  6.       };   

6、msg_controllen :cmsghdr 结构体可能不止一个;

7、flags : 一般设置为0即可;


直接上代码:

client.c

[cpp]  view plain  copy
  1. #include <stdio.h>  
  2. #include <unistd.h>  
  3. #include <stdlib.h>  
  4. #include <stddef.h>  
  5. #include <string.h>  
  6. #include <sys/types.h>  
  7. #include <errno.h>  
  8. #include <sys/un.h>  
  9. #include <sys/socket.h>  
  10. #include <netinet/in.h>  
  11. #include <sys/epoll.h>  
  12. #include <fcntl.h>  
  13.   
  14. #define UNIXSTR_PATH "foo.socket"  
  15. #define OPEN_FILE  "test"  
  16.   
  17. int main(int argc, char *argv[])  
  18. {  
  19.     int clifd;  
  20.     struct sockaddr_un servaddr;  //IPC  
  21.     int ret;  
  22.     struct msghdr msg;  
  23.     struct iovec iov[1];  
  24.     char buf[100];  
  25.     union {  //保证cmsghdr和msg_control对齐  
  26.         struct cmsghdr cm;  
  27.         char control[CMSG_SPACE(sizeof(int))];  
  28.     } control_un;  
  29.     struct cmsghdr *pcmsg;  
  30.     int fd;  
  31.   
  32.     clifd  = socket(AF_UNIX, SOCK_STREAM, 0) ;  
  33.     if   ( clifd  <  0 ) {  
  34.         printf ( "socket failed.\n" ) ;  
  35.         return  - 1 ;  
  36.     }  
  37.   
  38.     fd  =  open(OPEN_FILE ,O_CREAT | O_RDWR, 0777);  
  39.     if( fd  <  0 ) {  
  40.         printf("open test failed.\n");  
  41.         return -1;  
  42.     }  
  43.   
  44.     bzero (&servaddr, sizeof(servaddr));  
  45.     servaddr.sun_family = AF_UNIX;  
  46.     strcpy ( servaddr.sun_path, UNIXSTR_PATH);  
  47.   
  48.     ret = connect(clifd, (struct sockaddr*)&servaddr, sizeof(servaddr));  
  49.     if(ret < 0) {  
  50.         printf ( "connect failed.\n" ) ;  
  51.         return 0;  
  52.     }  
  53.     //udp需要,tcp无视  
  54.     msg.msg_name = NULL;  
  55.     msg.msg_namelen = 0;  
  56.     iov[0].iov_base = buf;  
  57.     iov[0].iov_len = 100;  
  58.     msg.msg_iov = iov;  
  59.     msg.msg_iovlen = 1;  
  60.     //设置缓冲区和长度  
  61.     msg.msg_control = control_un.control;  
  62.     msg.msg_controllen = sizeof(control_un.control);  
  63.     //直接通过CMSG_FIRSTHDR取得附属数据  
  64.     pcmsg = CMSG_FIRSTHDR(&msg);  
  65.     pcmsg->cmsg_len = CMSG_LEN(sizeof(int));  
  66.     pcmsg->cmsg_level = SOL_SOCKET;  
  67.     pcmsg->cmsg_type = SCM_RIGHTS;  //指明发送的是描述符  
  68.     *((int*)CMSG_DATA(pcmsg)) == fd;  //把描述符写入辅助数据  
  69.   
  70.     ret = sendmsg(clifd, &msg, 0);  //send filedescriptor  
  71.     printf ("ret = %d, filedescriptor = %d\n", ret, fd);  
  72.     return 0 ;  
  73. }  

server.c

[cpp]  view plain  copy
  1. #include <stdio.h>  
  2. #include <unistd.h>  
  3. #include <stdlib.h>  
  4. #include <stddef.h>  
  5. #include <string.h>  
  6. #include <sys/types.h>  
  7. #include <errno.h>  
  8. #include <sys/un.h>  
  9. #include <sys/socket.h>  
  10. #include <netinet/in.h>  
  11. #include <sys/epoll.h>  
  12. #include <fcntl.h>  
  13.   
  14. #define UNIXSTR_PATH "foo.socket"  
  15.   
  16. int main(int argc, char *argv[])  
  17. {  
  18.     int clifd, listenfd;  
  19.     struct sockaddr_un servaddr, cliaddr;  
  20.     int ret;  
  21.     socklen_t clilen;  
  22.     struct msghdr msg;  
  23.     struct iovec iov[1];  
  24.     char buf [100];  
  25.     char  *testmsg = "test msg.\n";  
  26.   
  27.     union {  //对齐  
  28.         struct cmsghdr cm;  
  29.         char control[CMSG_SPACE(sizeof(int))];  
  30.     }  control_un;  
  31.     struct cmsghdr  * pcmsg;  
  32.     int  recvfd;  
  33.   
  34.     listenfd  =  socket ( AF_UNIX ,  SOCK_STREAM ,  0 ) ;  
  35.     if(listenfd < 0) {  
  36.         printf ( "socket failed.\n" ) ;  
  37.         return  -1;  
  38.     }  
  39.   
  40.     unlink(UNIXSTR_PATH) ;  
  41.   
  42.     bzero (&servaddr, sizeof(servaddr));  
  43.     servaddr.sun_family = AF_UNIX;  
  44.     strcpy ( servaddr.sun_path ,  UNIXSTR_PATH ) ;  
  45.   
  46.     ret  =  bind ( listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));  
  47.     if(ret < 0) {  
  48.         printf ( "bind failed. errno = %d.\n" ,  errno ) ;  
  49.         close(listenfd);  
  50.         return  - 1 ;  
  51.     }  
  52.   
  53.     listen(listenfd, 5);  
  54.   
  55.     while(1) {  
  56.         clilen = sizeof( cliaddr );  
  57.         clifd = accept( listenfd, (struct sockaddr*)&cliaddr , &clilen);  
  58.         if ( clifd < 0 ) {  
  59.             printf ( "accept failed.\n" ) ;  
  60.             continue ;  
  61.         }  
  62.   
  63.         msg.msg_name  = NULL;  
  64.         msg.msg_namelen  = 0;  
  65.         //设置数据缓冲区  
  66.         iov[0].iov_base = buf;  
  67.         iov[0].iov_len = 100;  
  68.         msg.msg_iov = iov;  
  69.         msg.msg_iovlen = 1;  
  70.         //设置辅助数据缓冲区和长度  
  71.         msg.msg_control = control_un.control;  
  72.         msg.msg_controllen  =  sizeof(control_un.control) ;  
  73.         //接收  
  74.         ret = recvmsg(clifd , &msg, 0);  
  75.         if( ret <= 0 ) {  
  76.             return ret;  
  77.         }  
  78.         //检查是否收到了辅助数据,以及长度  
  79.         if((pcmsg = CMSG_FIRSTHDR(&msg) ) != NULL && ( pcmsg->cmsg_len == CMSG_LEN(sizeof(int)))) {  
  80.             if ( pcmsg->cmsg_level  !=  SOL_SOCKET ) {  
  81.                 printf("cmsg_leval is not SOL_SOCKET\n");  
  82.                 continue;  
  83.             }  
  84.   
  85.             if ( pcmsg->cmsg_type != SCM_RIGHTS ) {  
  86.                 printf ( "cmsg_type is not SCM_RIGHTS" );  
  87.                 continue;  
  88.             }  
  89.             //这就是我们接收的描述符  
  90.             recvfd = *((int*)CMSG_DATA(pcmsg));  
  91.             printf ( "recv fd = %d\n", recvfd );  
  92.   
  93.             write ( recvfd, testmsg, strlen(testmsg) + 1);  
  94.         }  
  95.     }  
  96.   
  97.     return 0 ;  
  98. }  

进程间传输文件描述符的fd是不一定相同的,在client里面是4,到达server的时候4已经被占用了,所以分配了5给它。

别再只懂send/recv了!手把手教你用sendmsg/recvmsg在Linux进程间传递文件描述符 本文深入探讨了Linux下使用`sendmsg`/`recvmsg`在进程间传递文件描述符的高级技术。通过详细解析`msghdr`结构和辅助数据机制,提供完整的实战代码示例,帮助开发者实现高效、安全的进程间通信,特别适用于多进程架构中的资源共享场景。 阅读详情

相关推荐

msg_control:用于处理套接字辅助数据的辅助函数

msg_control 这些辅助函数操作套接字辅助数据。 它们处理 msghdr 的 msg_control 和 msg_conrollen 成员,并保留结构的其余部分。 /* Allocate buffer for control data. The buffer will be of size zero, however, to minimise number of (re)allocations you should specify the capacity in such a way as o fit all the ancillary data. Returns 0 in case of success, -1 if the buffer cannot be allocated. */ void msg_control_init (struct msghd

Linux高级进程编程———在任意两个进程间传递文件描述符:使用 sendmsg 和 recvmsg 实现

/* 本程序实现子进程打开一个文件描述符,然后将其传递给父进程,父进程通过其获得文件内容 */ #include<sys/socket.h> #include<fcntl.h> #include<stdio.h> #include<unistd.h> #include<stdlib.h> #include<assert.h> #include<string.h> static const int CONTROL_LEN =

m0_51551385的博客 3968

告别抓包:一个Xposed模块教你监控抖音App的本地数据变化

本文详细介绍了如何利用Xposed框架开发模块,实现抖音App本地数据监控的技术方案。通过Hook关键方法,开发者可以实时获取用户信息、推荐算法参数等核心数据,无需Root设备即可高效调试。文章包含完整的环境配置、代码实现和优化技巧,为移动应用开发与测试提供创新解决方案。

weixin_27015733的博客 385

高级IO函数

在I/O操作上设置超时 在涉及套接字的I/O操作上设置超时的方法有以下三种。 (1)调用alarm,它在指定超时期满时产生SIGALRM信号。这个方法涉及信号处理,而信号处理在不同的实现上存在差异,而且可能干扰进程中现有的alarm调用。 (2)在select中阻塞等待I/O (select有内置的时间限制),以此代替直接阻塞在read或 write 调用上。 (3)使用较新的SO_RCVTIMEO和SO_SNDTIMEO套接字选项。这个方法的问题在于并非所有实现都支持这两个套接字选项。 前两个技术适用于任

weixin_45673259的博客 1018

基于Freertos与lwip移植FreeModbusTcp协议

基于FreeRTOS的N32G457VEL7之LWIP网络协议栈移植-优快云博客。

Dd_456456的博客 3239

delphi android发送与接收广播

在发送广播时,使用`SendBroadcast`函数,并传入广播的Action。在接收广播时,创建一个继承自`TAndroidBroadcastReceiver`的类,并在`onReceive`方法中处理接收到的广播。然后,使用`RegisterBroadcastReceiver`函数注册广播接收器,并在`UnregisterBroadcastReceiver`函数中取消注册。请注意替换示例代码中的`YOUR_ACTION`为实际的广播Action。// 处理接收到的广播。

GuoGuoABC 1207

socket通信中,使用sengmsg函数能解决多线程无法同时使用同一个fd的问题吗?

在socket通信中,使用sendmsg函数并不能解决多线程无法同时使用同一个fd的问题。 sendmsg函数是用来发送消息的,它可以将多个数据分散在不同的缓冲区中,并一次性发送出去。但是,它并没有解决多线程同时使用同一个fd的问题。在多线程中,如果多个线程同时使用同一个fd,就会发生竞争条件,导致数据不一致或者出现其他问题。 为了解决多线程同时使用同一个fd的问题,可以采用以下方法: 1.使用线...

weixin_35750953的博客 414

100道测试工程师笔试的Linux笔试题及答案_网络安全工程师关于linux的笔试大题

47.Linux系统中,一般把命令 ls 定义为 ls --color 的别名,以便以不同颜色来标识不同类型的文件。但是,如何能够使用原先的ls命令?83.在xdm的配置目录中,哪个文件用来设置在用户通过xdm登录后自动起动的应用程序?45.你的系统使用增量备份策略,当需要恢复系统时,你需要按什么顺序恢复备份数据?84.命令 netstat -a 停了很长时间没有响应,这可能是哪里的问题?51.Linux中,提供TCP/IP包过滤功能的软件叫什么?88.TCP/IP中,哪个协议是用来进行IP自动分配的?

2401_84247760的博客 1056

【Linux C | 网络编程】进程间传递文件描述符socketpair、sendmsg、recvmsg详解

我们的目的是,实现进程间传递文件描述符,是指 A进程打开文件fileA,获得文件描述符为fdA,现在 A进程要通过某种方法,传递fdA,使得另一个进程B,获得一个新的文件描述符fdB,这个fdB在进程B中的作用,跟fdA在进程A中的作用一样。即在 fdB上的操作,即是对fileA的操作。可能很多人想到的是用管道pipe来实现,但是却没想象的那么容易。

qq_42037383的博客 1688

ZYNQ裸机LWIP双网口实现

文章目录前言一、LWIP双网口二、使用步骤1.部分说明2.部分代码总结 前言 一、LWIP双网口 由于项目需要多通讯口,查阅资料发现lwip支持多网口操作。于是,就开搞了。 二、使用步骤 1.部分说明 利用xemac_add函数在网卡链表中添加一个网卡,即使用netif块重复xemac_add操作。 先用轮询的方式实现双网口,后期修改为中断模式 2.部分代码 导入官方例程LWip echo server, 修改main函数,增加一个netif块 #if LWIP_IPV6==0 #if L..

weixin_35865280的博客 1万+

告别调参烦恼:用Simulink手把手实现自适应模糊PID温度控制(附模型下载)

本文详细介绍了如何使用Simulink实现自适应模糊PID温度控制,解决传统PID调参难题。通过模糊推理引擎动态调整PID参数,系统能自动适应不同工况,显著提升控制精度和响应速度。文章包含完整的建模步骤、参数优化技巧和工业应用扩展,并附赠可下载模型,帮助工程师快速掌握这一智能控制技术。

weixin_30872499的博客 154

进程间传递文件描述符--sendmsg,recvmsg,struct msghdr,struct iovec

UNIX域套接字可以在同一台主机上各进程之间传递文件描述符。下面先来看两个函数:[cpp] view plain copy#include &lt;sys/types.h&gt;   #include &lt;sys/socket.h&gt;     ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);   ssize_...

二进制君 1759

QGIS基于快鸟(QuickBird)影像统计小麦种植面积

​01数据情况 本次选用某地4月份快鸟(QuickBird)影像为例,使用QGIS演示提取小麦播种情况,并按照200米*200米分区计算种植面积的过程。 注:本文对应的操作视频作为今天第二篇推送同时发布,习惯看视频的朋友可以点击观看。 附数据压缩包: 链接:https://pan.baidu.com/s/1JVUS8uAOR61RxC1n9Or9_w 提取码:qgis 含快鸟影像QB_subset.tif和200*200米分区矢量图层200Mgrid.shp。 ...

QGISClass的博客 1979

进程间传递文件描述符--sendmsg,recvmsg(可用)

UNIX域套接字可以在同一台主机上各进程之间传递文件描述符。 下面先来看两个函数: #include #include ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

Android系统攻城狮 1373

Oracle数据库表空间使用情况查询

在Oracle数据库中,表空间(Tablespace)是用于存储表、索引和其他数据库对象的逻辑存储单元。了解表空间的使用情况对于数据库管理员和开发人员来说是非常重要的,因为它可以帮助他们监控数据库的空间使用情况并进行容量规划。本文将介绍如何查询Oracle数据库中的表空间使用情况。通过执行以上SQL查询语句,你可以获得Oracle数据库中表空间的使用情况、文件大小和表空间大小等信息。这些信息可以帮助你了解数据库的存储情况,并进行适当的优化和容量规划。查看表空间的数据文件和表空间大小。查看表空间的使用情况。

CsmbPascal的博客 859

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

0725,进程间传递文件描述符,socketpair + sendmsg/recvmsg

我要碎掉了我要碎掉了我要碎掉了

qq_51583806的博客 647

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

保姆级教程:用sendmsg/recvmsg在Linux进程间传递文件描述符(附完整C代码)

本文详细介绍了在Linux系统中使用sendmsg/recvmsg进行进程间文件描述符传递的完整实现方法。通过SCM_RIGHTS控制消息,开发者可以高效地在多进程间共享文件操作权限,避免数据拷贝和同步问题。文章包含完整的C代码示例,从原理讲解到实战演示,帮助读者快速掌握这一高级IPC技术。

weixin_29735819的博客 315

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

linux 进程间文件描述符传递,进程间传递文件描述符fd

众所周知,子进程会继承父进程已经打开的文件描述符fd,但是fork之后的是不会被继承的,这个时候是否无能无力了?答应是NO。Linux提供了一个系统调用sendmsg,借助它,可以实现进程间传递文件描述符fd,而且不仅限于父进程到子进程。sendmsg函数的原型如下:#includessize_tsendmsg(intsocket,conststructmsghdr*message,...

weixin_28825959的博客 1880

Linux 进程间传递文件描述符

文章目录文件描述符文件数据结构共享文件UNIX域socket实现传递文件描述符 进程间传递打开的文件描述符,并不是传递文件描述符的值。先说一下文件描述符。 文件描述符 对内核来说,所有打开的文件都会通过文件描述符引用,文件描述符在进程中是一个非负整数,文件描述符在进程中是从0开始,默认0与标准输入关联、1与标准输出关联、2与标准出错关联。之后进程每打开一个文件或者创建一个新文件的时候,内核都会向进程返回一个文件描述符来表示这个文件,文件描述符是递增的。文件描述符的值与文件没有必然的联系,只是该文件在进程中的

肥宅快乐博客 1889

美妙的文件描述符传递(recvmsg sendmsg)

我们知道父进程在子进程被fork出来之前打开的文件描述符是能被子进程继承下来的,但是一旦子进程已经创建后,父进程打开的文件描述符要怎样才能传递给子进程呢?Unix提供相应的技术来满足这一需求,这就是同一台主机上进程间的文件描述符传递,很美妙而且强大的技术。想象一下我们试图实现一个服务器,接收多个客户端的连接,我们欲采用多个子进程并发的形式来处理多客户端的同时连接,这时候我们可能有两种想法:1、

1926

Linux网络编程——进程间传递文件描述符

先引入一个例子,该程序的目的是子进程向父进程传递文件描述符,并通过该文件描述符读取buf。 #include <func.h> int main(){ int fds[2]; pipe(fds); if(!fork()){ close(fds[1]); int fd; read(fds[0], &fd, ...

weixin_30437481的博客 261
上一篇: 进程间传递描述符
下一篇: TCP/IP报文头部结构整理
一一风浪
博客等级 码龄18年 197粉丝 65原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值