linux进程间文件描述符传递,linux进程线程间通信:传递文件描述符

问题描述

主进程中创建一个子进程和两个线程,每个线程负责accept连接,用socketpair创建了通信管道,在主进程中把服务端socket及管道的其中一个套接字传递给了线程,本来想在线程中把客户端socket文件描述符通过sendmsg函数传递给子进程,但是提示无效的文件描述符。

相关代码

struct mypara

{

int tcp_sock;//参数1

int pip_sock;//参数2

};

int main(int argc, char const *argv[])

{

int serv_sock;

struct sockaddr_in serv_adr;

pthread_t t_id[NUM_THREAD];

int j,k,state,str_len,fd,rv;

pid_t pid;

int fds[2];

struct sigaction act;

struct mypara pstru;

char buf[BUF_SIZE];

if(argc!=2)

{

printf("Usage: %s \n", argv[0]);

exit(1);

}

//注册信号处理函数

act.sa_handler=read_childproc;

sigemptyset(&act.sa_mask);

act.sa_flags=0;

state=sigaction(SIGCHLD,&act,0);

serv_sock=socket(PF_INET,SOCK_STREAM,0);

memset(&serv_adr,0,sizeof(serv_adr));

serv_adr.sin_family=AF_INET;

serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);

serv_adr.sin_port=htons(atoi(argv[1]));

if(bind(serv_sock,(struct sockaddr *)&serv_adr,sizeof(serv_adr))==-1)

error_handling("bind()...error");

if(listen(serv_sock,5)==-1)

error_handling("listen()...error");

//pipe(fds); //创建管道

socketpair(AF_UNIX, SOCK_STREAM, 0, fds);

if (rv < 0)

{

printf("Call socketpair error, errno is %d\n", errno);

return errno;

}

pid=fork();

pstru.tcp_sock = serv_sock;

pstru.pip_sock = fds[1];

if(pid==0) /*子进程处理逻辑*/

{

close(serv_sock);//子进程销毁服务端套接字,因为不需要使用

puts("work start...");

while(1)

{

fd = recv_fd(fds[0]);

str_len = read(fds[0],buf,BUF_SIZE);//读

if (str_len > 0)

puts(buf);

if (fd > 0){

write(fd,buf,str_len);

}

}

return 0;

}

for (j = 0; j < NUM_THREAD; j++)

{

pthread_create(&t_id[j],NULL,handle_clnt,(void*)&pstru);

}

for(k=0;k

pthread_join(t_id[k],NULL);

return 0;

}

//每个线程执行的main入口函数

void * handle_clnt(void * arg)

{

struct mypara *pstru;

pstru = (struct mypara *) arg;

int serv_sock = pstru->tcp_sock; //tcp服务端描述符

int pip_sock = pstru->pip_sock; //管道描述符

int clnt_sock;

struct sockaddr_in clnt_adr;

socklen_t adr_sz;

int str_len,i;

char buf[BUF_SIZE];//接收数据

struct epoll_event *ep_events;

struct epoll_event event;

int epfd,event_cnt;

epfd=epoll_create(EPOLL_SIZE);

ep_events=malloc(sizeof(struct epoll_event)*EPOLL_SIZE);

event.events=EPOLLIN;

event.data.fd=serv_sock;

epoll_ctl(epfd,EPOLL_CTL_ADD,serv_sock,&event);

while(1)

{

event_cnt=epoll_wait(epfd,ep_events,EPOLL_SIZE,-1);

if(event_cnt==-1)

{

puts("epoll_wait() error");

break;

}

puts("return epoll_wait");

for(i=0;i

{

if(ep_events[i].data.fd==serv_sock)

{

adr_sz=sizeof(clnt_adr);

clnt_sock=accept(serv_sock,(struct sockaddr*)&clnt_adr,&adr_sz);

event.events=EPOLLIN;

event.data.fd=clnt_sock;

epoll_ctl(epfd,EPOLL_CTL_ADD,clnt_sock,&event);

printf("connected client: %d \n", clnt_sock);

}

else

{

str_len=read(ep_events[i].data.fd,buf,BUF_SIZE);

if(str_len==0)

{

epoll_ctl(epfd,EPOLL_CTL_DEL,ep_events[i].data.fd,NULL);

close(ep_events[i].data.fd);

printf("closed client: %d \n", ep_events[i].data.fd);

}

else

{

write(pip_sock,buf,str_len);//写

send_fd(pip_sock, ep_events[i].data.fd);

//write(ep_events[i].data.fd,buf,str_len);

}

}

}

}

close(serv_sock);

close(epfd);

return NULL;

}

void read_childproc(int sig)

{

pid_t pid;

int status;

pid=waitpid(-1,&status,WNOHANG);

printf("removed proc id: %d \n", pid);

}

void error_handling(char *msg)

{

fputs(msg,stderr);

fputc('\n',stderr);

exit(1);

}

int send_fd(int fd, int fd_to_send)

{

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 ret;

//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_to_send; //把描述符写入辅助数据

ret = sendmsg(fd, &msg, 0);

if(ret < 0) {

printf("sendmsg error, errno is %d\n", errno);

printf("%s\n",strerror(errno));

printf ("ret = %d, filedescriptor = %d\n", ret, fd_to_send);

return errno;

}

return 0;

}

int recv_fd(int fd)

{

struct msghdr msg;

struct iovec iov[1];

char buf[100];

int ret,recvfd;

union { //对齐

struct cmsghdr cm;

char control[CMSG_SPACE(sizeof(int))];

} control_un;

struct cmsghdr * pcmsg;

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(fd , &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");

return -1;

}

if ( pcmsg->cmsg_type != SCM_RIGHTS ) {

printf ( "cmsg_type is not SCM_RIGHTS" );

return -1;

}

//这就是我们接收的描述符

recvfd = *((int*)CMSG_DATA(pcmsg));

return recvfd;

}

return -1;

}

错误信息:

sendmsg error, errno is 9

Bad file descriptor

ret = -1, filedescriptor = 8

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值