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

下面先来看两个函数:

#include <sys/types.h>
#include <sys/socket.h> ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

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

struct msghdr { void         *msg_name;       /* optional address */ socklen_t     msg_namelen;    /* size of address */ struct iovec *msg_iov;        /* scatter/gather array */ size_t        msg_iovlen;     /* # elements in msg_iov */ void         *msg_control;    /* ancillary data, see below */ size_t        msg_controllen; /* ancillary data buffer len */ int           msg_flags;      /* flags on received message */
}; 

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

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

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

struct iovec { void  *iov_base;    /* Starting address */ size_t iov_len;     /* Number of bytes to transfer */ };

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

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

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

 struct cmsghdr { socklen_t cmsg_len;    /* data byte count, including header */ int       cmsg_level;  /* originating protocol */ int       cmsg_type;   /* protocol-specific type */ /* followed by unsigned char cmsg_data[]; */ }; 

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

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

直接上代码:

client.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <fcntl.h>#define UNIXSTR_PATH "foo.socket"
#define OPEN_FILE  "test"int main(int argc, char *argv[])
{int clifd;struct sockaddr_un servaddr;  //IPCint ret;struct msghdr msg;struct iovec iov[1];char buf[100];union {  //保证cmsghdr和msg_control对齐struct cmsghdr cm;char control[CMSG_SPACE(sizeof(int))];} control_un;struct cmsghdr *pcmsg;int fd;clifd  = socket(AF_UNIX, SOCK_STREAM, 0) ;if   ( clifd  <  0 ) {printf ( "socket failed.\n" ) ;return  - 1 ;}fd  =  open(OPEN_FILE ,O_CREAT | O_RDWR, 0777);if( fd  <  0 ) {printf("open test failed.\n");return -1;}bzero (&servaddr, sizeof(servaddr));servaddr.sun_family = AF_UNIX;strcpy ( servaddr.sun_path, UNIXSTR_PATH);ret = connect(clifd, (struct sockaddr*)&servaddr, sizeof(servaddr));if(ret < 0) {printf ( "connect failed.\n" ) ;return 0;}//udp需要,tcp无视msg.msg_name = NULL;msg.msg_namelen = 0;iov[0].iov_base = buf;iov[0].iov_len = 100;msg.msg_iov = iov;msg.msg_iovlen = 1;//设置缓冲区和长度msg.msg_control = control_un.control;msg.msg_controllen = sizeof(control_un.control);//直接通过CMSG_FIRSTHDR取得附属数据pcmsg = CMSG_FIRSTHDR(&msg);pcmsg->cmsg_len = CMSG_LEN(sizeof(int));pcmsg->cmsg_level = SOL_SOCKET;pcmsg->cmsg_type = SCM_RIGHTS;  //指明发送的是描述符*((int*)CMSG_DATA(pcmsg)) == fd;  //把描述符写入辅助数据ret = sendmsg(clifd, &msg, 0);  //send filedescriptorprintf ("ret = %d, filedescriptor = %d\n", ret, fd);return 0 ;
}

server.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <fcntl.h>#define UNIXSTR_PATH "foo.socket"int main(int argc, char *argv[])
{int clifd, listenfd;struct sockaddr_un servaddr, cliaddr;int ret;socklen_t clilen;struct msghdr msg;struct iovec iov[1];char buf [100];char  *testmsg = "test msg.\n";union {  //对齐struct cmsghdr cm;char control[CMSG_SPACE(sizeof(int))];}  control_un;struct cmsghdr  * pcmsg;int  recvfd;listenfd  =  socket ( AF_UNIX ,  SOCK_STREAM ,  0 ) ;if(listenfd < 0) {printf ( "socket failed.\n" ) ;return  -1;}unlink(UNIXSTR_PATH) ;bzero (&servaddr, sizeof(servaddr));servaddr.sun_family = AF_UNIX;strcpy ( servaddr.sun_path ,  UNIXSTR_PATH ) ;ret  =  bind ( listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));if(ret < 0) {printf ( "bind failed. errno = %d.\n" ,  errno ) ;close(listenfd);return  - 1 ;}listen(listenfd, 5);while(1) {clilen = sizeof( cliaddr );clifd = accept( listenfd, (struct sockaddr*)&cliaddr , &clilen);if ( clifd < 0 ) {printf ( "accept failed.\n" ) ;continue ;}msg.msg_name  = NULL;msg.msg_namelen  = 0;//设置数据缓冲区iov[0].iov_base = buf;iov[0].iov_len = 100;msg.msg_iov = iov;msg.msg_iovlen = 1;//设置辅助数据缓冲区和长度msg.msg_control = control_un.control;msg.msg_controllen  =  sizeof(control_un.control) ;//接收ret = recvmsg(clifd , &msg, 0);if( ret <= 0 ) {return ret;}//检查是否收到了辅助数据,以及长度if((pcmsg = CMSG_FIRSTHDR(&msg) ) != NULL && ( pcmsg->cmsg_len == CMSG_LEN(sizeof(int)))) {if ( pcmsg->cmsg_level  !=  SOL_SOCKET ) {printf("cmsg_leval is not SOL_SOCKET\n");continue;}if ( pcmsg->cmsg_type != SCM_RIGHTS ) {printf ( "cmsg_type is not SCM_RIGHTS" );continue;}//这就是我们接收的描述符recvfd = *((int*)CMSG_DATA(pcmsg));printf ( "recv fd = %d\n", recvfd );write ( recvfd, testmsg, strlen(testmsg) + 1);}}return 0 ;
}

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

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

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

    进程间传递打开的文件描述符,并不是传递文件描述符的值.那么在传递时究竟传递了什么?我们要先搞明白这个问题. 1.文件描述符 文件描述符的值与文件没有任何联系,只是该文件在进程中的一个标识,所以同一文件 ...

  2. Linux 进程间传递文件描述符

    文章目录 文件描述符 文件数据结构 共享文件 UNIX域socket实现传递文件描述符 进程间传递打开的文件描述符,并不是传递文件描述符的值.先说一下文件描述符. 文件描述符 对内核来说,所有打开的文 ...

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

    在进行fork调用后,由于子进程会拷贝父进程的资源,所以父进程中打开的文件描述符在子进程中仍然保持着打开,我们很容易的就将父进程的描述符传递给了子进程.但是除了这种情况下,如果想将某个父进程在子进程创 ...

  4. android进程间传递文件描述符原理

    在Linux中,进程打开一个文件,返回一个整数的文件描述符,然后就可以在这个文件描述符上对该文件进行操作.那么文件描述符和文件到底是什么关系?进程使用的是虚拟地址,不同进程间是地址隔离的,如何在两个进 ...

  5. 不相干进程之间传递文件描述符

    #include <sys/socket.h> #include <fcntl.h> #include <stdio.h> #include <unistd. ...

  6. Linux的辅助数据和传递文件描述符

    简介 首先,明确传递文件描述符的意义.一般来说,在多进程网络编程中,我们设置一个主进程用于监听新来的连接,设置一个进程池,用于处理这些连接.但是,与线程池不同,进程池各个进程之间的空间是独立的,直接共 ...

  7. 线程共享的环境包括:进程代码段、进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯)、进程打开的文件描述符、信号的处理器、进程的当前目录和进程用户ID与进程组ID。 进程拥有这

    线程共享的环境: 进程代码段.进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯).进程打开的文件描述符.信号的处理器.进程的当前目录和进程用户ID与进程组ID. 进程拥有这许多共性的 ...

  8. FORK()子进程对父进程打开的文件描述符的处理

    总的来说,子进程将复制父亲进程的数据段,BSS段,代码段,堆空间,栈空间和文件描述符.而对于文件技术符关联内核文件表项(即STRUCT FILE结构),则是采取了共享的方式. 下面代码说明. I值分离 ...

  9. fork()子进程与父进程之间的文件描述符问题

    在C程序中,文件由文件指针或者文件描述符表示.ISO C的标准I/0库函数(fopen, fclose, fread, fwrite, fscanf, fprintf等)使用文件指针,UNIX的I/O ...

最新文章

  1. 详解JavaScript中的this
  2. ubuntu下eclipse新建项目没有java project的解决办法
  3. 基于 ELK Stack 和 Spark Streaming 的日志处理平台设计与实现
  4. Angularjs1.x 项目结构
  5. linux遍历目录源代码
  6. 数据同步到redis中时候需要 需要给关联的表增加id 如果是一对多 则增加list存储id 如果是一个 则增加一个字段 ;目的是便于取值...
  7. as和强制类型转换的区别
  8. C#LeetCode刷题之#874-模拟行走机器人​​​​​​​(Walking Robot Simulation)
  9. 安卓学习笔记39:浏览网页、网页与安卓通信
  10. Java servlet ajax
  11. python棋盘覆盖问题_棋盘覆盖问题可视化动图——python
  12. springcloud工作笔记099---springboot集成netty,进行线程管理,socket通讯
  13. 【算法导论】贪心算法,递归算法,动态规划算法总结
  14. linux能力集机制,linux能力机制
  15. VB之Collection---Collection集合类
  16. Kaleidoscope for Mac(文件和图像比较工具)
  17. npm ERR! Error: EPERM: operation not permitted问题解决
  18. 检测屏幕颜色显示坏点的一个小方法。
  19. vue-element-admin——登录页面添加自定义背景
  20. 为何Set检索效率低下

热门文章

  1. Java自增原子性问题(测试Volatile、AtomicInteger)
  2. 转一篇:如何快速的修改参考文献
  3. 2022年IT热门能力
  4. Sweet Home 3D 是Web三维效果图
  5. SpringAMQP+RabbitMQ调试中的问题解决
  6. 403 常见原因 java_科普 httpClient 403 Forbidden (JAVA方向分析)
  7. 【机器学习】基于GBDT的数据回归及python实现
  8. ios去掉字符串中的某个字符_iOS如何过滤掉文本中特殊字符
  9. python基础语法加爬虫精进_从Python安装到语法基础,这才是初学者都能懂的爬虫教程...
  10. Leetcode-Pascal's Triangle