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
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值