Linux 下 不同进程之间传递描述符

 1. 接收传递描述符,demo(fd_read_file.c)

  • 创建流管道
  • fork并exec
  • 父进程等待子进程
  • 接收描述符
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include <sys/socket.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/uio.h>
#include <errno.h>


#define HAVE_MSGHDR_MSG_CONTROL
#define	BUFFSIZE	8192	/* buffer size for reads and writes */

ssize_t read_fd(int fd, void *ptr, size_t nbytes, int *recvfd)
{
	struct msghdr	msg;
	struct iovec	iov[1];
	ssize_t			n;

#ifdef	HAVE_MSGHDR_MSG_CONTROL
	union {
	  struct cmsghdr	cm;
	  char				control[CMSG_SPACE(sizeof(int))];
	} control_un;
	struct cmsghdr	*cmptr;

	msg.msg_control = control_un.control;
	msg.msg_controllen = sizeof(control_un.control);
#else
	int				newfd;

	msg.msg_accrights = (caddr_t) &newfd;
	msg.msg_accrightslen = sizeof(int);
#endif

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

	iov[0].iov_base = ptr;
	iov[0].iov_len = nbytes;

	msg.msg_iov = iov;
	msg.msg_iovlen = 1;

	if ( (n = recvmsg(fd, &msg, 0)) <= 0) {
		return(n);
    }

#ifdef	HAVE_MSGHDR_MSG_CONTROL
	if ( (cmptr = CMSG_FIRSTHDR(&msg)) != NULL &&
	    cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
		if (cmptr->cmsg_level != SOL_SOCKET)
			// err_quit("control level != SOL_SOCKET");
			printf("control level != SOL_SOCKET\n");
		if (cmptr->cmsg_type != SCM_RIGHTS)
			// err_quit("control type != SCM_RIGHTS");
			printf("control type != SCM_RIGHTS\n");
		*recvfd = *((int *) CMSG_DATA(cmptr));
	} else
		*recvfd = -1;		/* descriptor was not passed */
#else
/* *INDENT-OFF* */
	if (msg.msg_accrightslen == sizeof(int))
		*recvfd = newfd;
	else
		*recvfd = -1;		/* descriptor was not passed */
/* *INDENT-ON* */
#endif

	return(n);
}
/* end read_fd */



int my_open(const char *pathname, int mode)
{
    int fd, sockfd[2], status;
    pid_t   childpid;
    char    c, argsockfd[10], argmode[10];

    /* 创建一个流管道, 返回两个描述符 */
    socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);

    if((childpid = fork()) == 0) { 
        /* child process */
        close(sockfd[0]);
        snprintf(argsockfd, sizeof(argsockfd), "%d", sockfd[1]);
        snprintf(argmode, sizeof(argmode), "%d", mode);

        /* 执行openfile程序 */
        execl("./openfile", "openfile", argsockfd, pathname, argmode, (char *)NULL);
        printf("execl error\n");

    }

	/* parent process - wait for the child to terminate */
    close(sockfd[1]);
    waitpid(childpid, &status, 0);

    if(WIFEXITED(status) == 0) {
        printf("child did not terminate\n");
    }

    /* 回读f */
    if(status = WEXITSTATUS(status) == 0) {
        read_fd(sockfd[0], &c, 1, &fd);

    } else {
        errno = status;
        fd = -1;
    }

    close(sockfd[0]);
    return(fd);
}

int main(int argc, char *argv[])
{
    int fd, n;
    char buff[BUFFSIZE];

    if(argc != 2) {
        printf("usage: mycat <pathname>\n");
    }

    /* 以追加方式打开文件,没有就创建 */
    if((fd = my_open(argv[1], O_RDWR|O_CREAT|O_APPEND)) < 0) {
        printf("cannot open %s\n", argv[1]);
    }

    while((n = read(fd, buff, BUFFSIZE)) > 0) {
        write(STDOUT_FILENO, buff, n);
    }

    exit(0);
}

2. 打开文件描述符并传递。demo(fd_open_file.c)

  • 命令行参数
  • 打开文件
  • 传递会描述符
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include <sys/socket.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/uio.h>
#include <errno.h>


#define HAVE_MSGHDR_MSG_CONTROL
#define	BUFFSIZE	8192	/* buffer size for reads and writes */

ssize_t write_fd(int fd, void *ptr, size_t nbytes, int sendfd)
{
	struct msghdr	msg;
	struct iovec	iov[1];

#ifdef	HAVE_MSGHDR_MSG_CONTROL
	union {
	  struct cmsghdr	cm;
	  char				control[CMSG_SPACE(sizeof(int))];
	} control_un;
	struct cmsghdr	*cmptr;

	msg.msg_control = control_un.control;
	msg.msg_controllen = sizeof(control_un.control);

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

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

	iov[0].iov_base = ptr;
	iov[0].iov_len = nbytes;
	msg.msg_iov = iov;
    msg.msg_iovlen = 1;


	return(sendmsg(fd, &msg, 0));
}
/* end write_fd */



int main(int argc, char *argv[])
{
    int fd;

    if(argc != 4) {
        printf("openfile <sockfd#> <filename> <mode>\n");
    }

    printf("file = %s, %s\n", argv[2], argv[3]);
    if((fd = open(argv[2], atoi(argv[3]), 0666)) < 0) {
        exit((errno > 0) ? errno : 255);
    }

    /* 向文件中写入测试数据 */
    write(fd, "It's a test\n", sizeof("It's a test\n")-1);
    lseek(fd, 0, SEEK_SET);

    if(write_fd(atoi(argv[1]), "", 1, fd) < 0) {
        printf("write_fd error = %d\n", errno);
        exit((errno > 0) ? errno : 255);
    }

    exit(0);


}

3. 演示

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
千里马8年Android系统及应用开发经验,曾担任过美国unokiwi公司移动端技术总监兼架构师,对系统开发,性能优化,应用高级开发有深入的研究,Android开源定制ROM Lineage的贡献者之一,国内首家线下开辟培训Android Framework课程,拥有2年的Android系统培训经验。成为腾讯课堂专业负责android framework课程分享第一人,致力于提高国内android Framework水平Android Framework领域内是国内各大手机终端科技公司需要的人才,应用开发者都对Android系统充满着好奇,其中的binder是重中之重,都说无binder无Android,binde是Android系统的任督二脉。课程水平循序渐进,由中级再到高级,满足各个层次水平的android开发者。1、灵活使用binder进程通信,在app端对它的任何api方法等使用自如2、可以单独分析android系统源码中任何binder部分,分析再也没有难度3、掌握binder驱动本质原理,及对应binder驱动怎么进行进程通信,及内存等拷贝方式数据等4、对binder从上层的java app端一直到最底层的内核binder驱动,都可以顺利理通5、针对系统开发过程中遇到的binder报错等分析方法,及binder bug案例学习6、针对面试官任何的binder问题都可以对答自如7、socket这种进程通信实战使用8、针对android源码中使用的socket源码轻松掌握9、android系统源码中最常见的socketpair中双向进程通信10、使用socket实现一个可以让app执行shell命令的程序

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值