多进程并发编程----进程间传递文件描述符案例

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<errno.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/socket.h>

int send_fd(int fd, void *ptr, size_t nbytes, int sendfd)
{
	struct msghdr	msg;
	struct iovec	iov[1];
	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;

	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));
}
int recv_fd(int sockfd,void *data,size_t size,int *fd){
	int num;
	struct msghdr msg;
	struct cmsghdr *cmsgptr;
	struct iovec vec[1];
	union{
		struct cmsghdr cmsg;
		char   control[CMSG_SPACE(sizeof(int))];	
	}control_un;
	
	msg.msg_control = control_un.control;
	msg.msg_controllen = sizeof(control_un.control);
	
	vec[0].iov_base=data;
	vec[0].iov_len=size;
	
	msg.msg_name=NULL;
	msg.msg_namelen=0;
	msg.msg_iov=vec;
	msg.msg_iovlen=1;	
	
	if((num=recvmsg(sockfd,&msg,0))==-1){
		printf("recvmsg error:%s\n",strerror(errno));
		return num;
	}
	
	if((cmsgptr=CMSG_FIRSTHDR(&msg))!= NULL && cmsgptr->cmsg_len==CMSG_LEN(sizeof(int))){
		if(cmsgptr->cmsg_level != SOL_SOCKET)
			printf("control level != SOL_SOCKET\n");
		if(cmsgptr->cmsg_type != SCM_RIGHTS)
			printf("control type != SCM_RIGHTS\n");
		*fd=*((int *)CMSG_DATA(cmsgptr));
	} 
	else
		*fd = -1;		/* descriptor was not passed */
	
	return num;
}

int main(){
	char filebuf[1024];
	char sendbuf[256];
	char recvbuf[256];
	int sockfd[2];
	int pid;
	int fd;
	int ret,state,num;
	ret=socketpair(AF_UNIX,SOCK_STREAM,0,sockfd);
	assert(ret!=-1);
	pid=fork();
	if(pid==0){
		close(sockfd[0]);
		fd=open("wordexp.c",O_RDONLY,0666);
		assert(fd!=-1);
		memset(sendbuf,0,sizeof(sendbuf));
		sprintf(sendbuf,"%s","hello,mm");
		num=send_fd(sockfd[1],sendbuf,sizeof(sendbuf),fd);
		close(fd);
		exit(5);	
	}
	waitpid(pid,&state,0);
	if(WIFEXITED(state)){
		printf("child is exited,state[%d]\n",WEXITSTATUS(state));
		close(sockfd[1]);
		memset(recvbuf,0,sizeof(recvbuf));
		num=recv_fd(sockfd[0],recvbuf,sizeof(recvbuf),&fd);
		printf("recvbuf:[%s]\n",recvbuf);
		memset(filebuf,0,sizeof(filebuf));
		read(fd,filebuf,sizeof(filebuf));
		printf("buf:[%s]\n",filebuf);
		close(fd);		
	}		
	
	return 0;
}

需要注意的是:

通常接收进程收到的套接字描述符的编号和发送进程的套接字描述符的编号会不一样,但这并没有任何问题。因为传递描述符并不是传递值的本身,而是在接收进程新建一个描述符并指向内核文件表中和发送进程发送的描述符相同的项。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值