linux进程之间传递句柄
参考网上的实现,进行了一点改进,本来想用FIFO实现的,后来发现不行,必须使用系统的sendmsg函数,代码格式有点乱,不过功能可以实现,改天有空整理一下~~
讲究看哈~
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include <strings.h>
#include<sys/wait.h>
#include <string.h>
#include <errno.h>
#include <sys/un.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/stat.h>
#define FIFO_NAME "/home/907684/my_fifo_file"
//#define BUFFER_SIZE PIPE_BUF
#define BUFFER_SIZE 10
#define TEN_MEG (1024*10)
#define CONTROLLEN sizeof (struct cmsghdr) + sizeof (int)
#define false 0
#define true 1
//异步写打开FIFO,必须先有读打开FIFO 否则会失败!
int proccess_num=-1;
void show_struct_byte(const char * buf, int len)
{
if (len <= 0) return;
int i;
printf("[%d]show struct len :%d. \r\n",proccess_num,len);
printf("[%d]show struct as string :%s. \r\n *** \r\n",proccess_num,buf);
for(i=0;i<len;i++)
{
printf("%d ",(int)(*buf++));
}
printf("\r\n[%d]finish show struct byte \r\n", proccess_num);
}
int send_sock_fd(int pipe_fd, int sock_fd)
{
if (pipe_fd <0 || sock_fd < 0) return false;
int bytes = 0,res;
int return_flag=true;
printf("[%d]enter send_sock_fd()... \r\n",proccess_num);
/*
char buf_str[] = "firt recieved Client speaking!\n";
//int ret = write(sock_fd, buf_str, sizeof(buf_str));
//write() 异常判断...
struct cmsghdr * cmptr = 0;
struct msghdr msg;
struct iovec iov[1];
char buf[2];
iov[0].iov_base = buf;
iov[0].iov_len = 2;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
cmptr = (struct cmsghdr *)malloc(sizeof(struct cmsghdr) + sizeof(int));
cmptr->cmsg_level = SOL_SOCKET;
cmptr->cmsg_type = SCM_RIGHTS;
cmptr->cmsg_len = sizeof(struct cmsghdr) + sizeof(int);
*(int *)CMSG_DATA(cmptr) = sock_fd;
msg.msg_control = cmptr;
msg.msg_controllen = sizeof(struct cmsghdr) + sizeof(int);
buf[1] = 0; buf[0] = 1;
*/
char tmpbuf[CONTROLLEN];
struct cmsghdr *cmptr = (struct cmsghdr *) tmpbuf;
struct iovec iov[1];
struct msghdr msg;
char buf[1];
iov[0].iov_base = buf;
iov[0].iov_len = 1;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_control = cmptr;
msg.msg_controllen = CONTROLLEN;
cmptr->cmsg_level = SOL_SOCKET;
cmptr->cmsg_type = SCM_RIGHTS;
cmptr->cmsg_len = CONTROLLEN;
*(int *)CMSG_DATA (cmptr) = sock_fd;
show_struct_byte((char *)&msg, sizeof(msg));
while (bytes < sizeof(msg))
{
printf("[%d]call write()... \r\n",proccess_num);
res = write(pipe_fd, (void *)&msg, sizeof(msg));
//res = sendmsg(pipe_fd,&msg,0);
printf("[%d]res = %d && errno = %d. \r\n",proccess_num,res,errno);
if (res == -1 )
{
if(errno == EAGAIN)
{
printf("[%d]write no data. try later... \r\n",proccess_num);
continue;
}
else
{
printf("[%d]write error. exit! \r\n",proccess_num);
fprintf(stderr, "Write error on pipe\r\n");
return_flag=false;
break;
}
}
bytes += res;
printf("[%d]write data:%d bytes, sleep...\r\n",proccess_num,res);
//sleep(9);
}
printf("[%d]Total %d bytes send to fifo. send sock_fd:%d. sizeof(msg):%d \r\n",proccess_num,bytes, sock_fd, sizeof(msg));
sleep(5);
//free(cmptr);
//close(sock_fd); //NOT close?
//close(pipe_fd); //NOT close?
return return_flag;
}
int read_sock_fd(int pipe_fd, int* sock_fd)
{
if (pipe_fd < 0 || sock_fd < 0) return false;
int bytes = 0, res;
int return_flag = true;
printf("[%d]enter read_sock_fd()... \r\n",proccess_num);
/*
//get client fd
char buf[2];
int newfd = -1;
struct iovec iov[1];
struct msghdr msg;
struct cmsghdr * cmptr = (struct cmsghdr *)malloc(sizeof(struct cmsghdr) + sizeof(int));
iov[0].iov_base = buf;
iov[0].iov_len = sizeof(buf);
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_control = cmptr;
msg.msg_controllen = sizeof(struct cmsghdr) + sizeof(int);
*/
char tmpbuf[CONTROLLEN];
struct cmsghdr *cmptr = (struct cmsghdr *) tmpbuf;
struct iovec iov[1];
struct msghdr msg;
char buf[1];
iov[0].iov_base = buf;
iov[0].iov_len = sizeof (buf);
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_control = cmptr;
msg.msg_controllen = CONTROLLEN;
printf("[%d] loop call read() fifo... \r\n", proccess_num);
while (bytes < sizeof(msg))
{
res = read(pipe_fd, &msg, sizeof(msg));
//res = recvmsg(pipe_fd,&msg,0);
sleep(2);
printf("[%d]res = %d && errno = %d. \r\n", proccess_num,res,errno);
if (res == -1 )
{
if(errno == EAGAIN)
{
//printf("read no data. try later... \r\n");
continue;
}
else
{
printf("[%d]read error. exit! \r\n",proccess_num);
fprintf(stderr, "Write error on pipe\r\n");
return_flag = false;
break;
}
}
bytes += res;
printf("[%d]read data:%d bytes.\r\n",proccess_num,res);
//sleep(9);
}
printf("[%d]%d bytes read from fifo. sizeof(msg):%d \r\n",proccess_num,bytes,sizeof(msg));
//get client socket
if (return_flag)
{
/*
printf("[%d]read fifo succeed. pase client fd.\r\n",proccess_num);
printf("[%d]*(int*)CMSG_DATA(cmptr):%d,cmptr:%d.\r\n",proccess_num,*(int*)CMSG_DATA(cmptr),cmptr);
show_struct_byte((char *)&msg, sizeof(msg));
*sock_fd = *(int*)CMSG_DATA(cmptr);
*/
printf("[%d]*(int*)CMSG_DATA(cmptr):%d,cmptr:%d.\r\n",proccess_num,*(int *)CMSG_DATA (cmptr),cmptr);
show_struct_byte((char *)&msg, sizeof(msg));
*sock_fd = *(int *)CMSG_DATA (cmptr);
printf("[%d]CMSG_FIRSTHDR(&msg) ret:%d (should not be 0!) \r\n", proccess_num,CMSG_FIRSTHDR(&msg));
}
else
{
printf("[%d]read fifo failed. set sock_fd = -1. \r\n",proccess_num);
*sock_fd = -1;
}
printf("[%d]get client fd:%d.\r\n",proccess_num,*sock_fd);
//sleep(5);
close(pipe_fd);
//close(sock_fd); //NOT close?
//free(cmptr);
return return_flag;
}
int init_fifo_write()
{
//***** fifo *****
int write_pipe_fd;
int res;
int open_mode = O_WRONLY|O_NONBLOCK;
int bytes = 0;
//char buffer[BUFFER_SIZE + 1] = "hello";
if (access(FIFO_NAME, F_OK) == -1)
{
res = mkfifo(FIFO_NAME, 0777);
if (res != 0)
{
fprintf(stderr, "Could not create fifo %s \r\n", FIFO_NAME);
return -1;
}
}
printf("[%d] write opeining FIFO :%s \r\n", proccess_num, FIFO_NAME);
//printf("fifo buffer size:%d",BUFFER_SIZE);
int read_fd = open(FIFO_NAME, O_RDONLY | O_NONBLOCK);
if (read_fd == -1)
{
printf("[%d]read open fifo file failed. exit. \r\n",proccess_num);
return -1;
}
write_pipe_fd = open(FIFO_NAME, O_WRONLY|O_NONBLOCK);
if (write_pipe_fd == -1)
{
printf("[%d]write open fifo file failed. exit. \r\n",proccess_num);
return -1;
}
printf("[%d]Process %d result %d\r\n",proccess_num, getpid(), write_pipe_fd);
return write_pipe_fd;
}
int init_fifo_read()
{
int read_pipe_fd;
int res;
int open_mode = O_RDONLY|O_NONBLOCK;
char buffer[BUFFER_SIZE + 1];
int bytes = 0;
memset(buffer, 0, sizeof(buffer));
printf("[%d] read opeining FIFO :%s \r\n", proccess_num, FIFO_NAME);
//printf("fifo buffer size:%d",BUFFER_SIZE);
read_pipe_fd = open(FIFO_NAME, O_RDONLY|O_NONBLOCK);
printf("Process %d result %d\r\n", getpid(), read_pipe_fd);
if (read_pipe_fd == -1)
{
printf("read open fifo file failed. exit. \r\n");
return -1;
}
printf("Process %d result %d\r\n", getpid(), read_pipe_fd);
return read_pipe_fd;
}
//***** fifo *****
//************************ send socket fd
static struct sockaddr_un addr = {0};
static int s_create_usockfd()
{
static char* path = "/home/907684/test/fd_send/share_fd";
int sockfd;
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, path);
sockfd = socket(PF_UNIX, SOCK_DGRAM, 0);
if(sockfd == -1)
{
printf("create unix sockfd failed, %d, %s\n", errno, strerror(errno));
return 0;
}
else
{
printf("create unix sockfd ok\n");
}
//还需要使用bind函数来创建S_IFSOCK类型文件!!!!!!
//否则可能提示文件不存在!!!
return sockfd;
}
static int s_send_fd(int sockfd, int fd)
{
struct msghdr msg = {0};
char ccmsg[CMSG_SPACE(sizeof(fd))];
struct cmsghdr* cmsg; int rv;
msg.msg_name = (struct sockaddr*)&addr;
msg.msg_namelen = sizeof(addr);
msg.msg_control = ccmsg;
msg.msg_controllen = sizeof(ccmsg);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
*(int*)CMSG_DATA(cmsg) = fd;
msg.msg_control = ccmsg;
msg.msg_controllen = cmsg->cmsg_len;
msg.msg_flags = 0;
printf("sendmsg file fd[%d] to socket fd[%d]\n",fd, sockfd);
rv = (sendmsg(sockfd, &msg, 0) != -1);
printf("sendmsg return %d \r\n",rv);
if(rv)
{
printf("sendmsg ok, file fd is %d\n", fd);
close(fd);
}
else
{
printf("sendmsg failed to socket fd[%d], errno[%d], error str:%s\n", sockfd, errno, strerror(errno));
}
printf("send fd[%d] to shared file finish.\r\n", fd);
return rv;
}
int get_fd_to_send()
{
char * file_shared_path = "/home/907684/test/fd_send/file_shared.txt";
int sfd = open(file_shared_path, O_CREAT|O_RDWR|O_TRUNC, 0644);
return sfd;
}
//************************ send socket fd
//************************ recv socket fd
static int r_create_usockfd(char* path)
{
struct sockaddr_un addr = {0};
int opt = 1;
int fd;
addr.sun_family = AF_UNIX;
unlink(path);
strcpy(addr.sun_path, path);
fd = socket(PF_UNIX, SOCK_DGRAM, 0);
if(bind(fd, (struct sockaddr*)&addr, sizeof(addr))){
printf("[%d]recv bind failed, %d, %s\n",proccess_num, errno, strerror(errno));
}
else{
printf("[%d]recv bind ok\n", proccess_num);
}
return fd;
}
static int r_recv_fd(int fd)
{
struct msghdr msg = {0};
int rv = 0;
int cfd = -1;
char ccmsg[CMSG_SPACE(sizeof(cfd))];
struct cmsghdr* cmsg;
msg.msg_control = ccmsg;
msg.msg_controllen = sizeof(ccmsg);
while(1){
rv = recvmsg(fd, &msg, 0);
if(rv == -1){
printf("recvmsg failed, return %d, %d, %s\n", rv, errno, strerror(errno));
sleep(1);
}
else{
printf("[%d]recvmsg ok.\n",proccess_num);
break;
}
}
cmsg = CMSG_FIRSTHDR(&msg);
int client_fd=*(int*)CMSG_DATA(cmsg);
printf("[%d]recieved client socket fd[%d].\n",proccess_num,client_fd);
return client_fd;
}
int get_share_fd()
{
int sfd = socket(AF_INET, SOCK_STREAM, 0);
sfd = socket(AF_INET, SOCK_STREAM, 0); // waste some fd
static char* path = "/home/907684/test/fd_send/share_fd";
int sockfd = r_create_usockfd(path);
int cfd = r_recv_fd(sockfd);
return cfd;
}
void send_msg_to_client(int cfd)
{
char* str = "This is the second proccess speaking.\n";
printf("[%d]write string to recieved file fd[%d]. string[%s]\r\n",proccess_num, cfd,str);
int res = write(cfd, str, strlen(str));
if(res<0)
{
printf("write error. res:%d\r\n",res);
}
}
//************************ recv socket fd
int main(int argc, char ** argv)
{
pid_t pid;
char *msg;
int n,i,j;
int exit_code;
int res=0,WR_fifo_fd,RD_fifo_fd;
//***** socket *****
int listenfd,connfd;
socklen_t clilen;
struct sockaddr_in cliaddr,servaddr;
listenfd = socket(AF_INET,SOCK_STREAM,0);
//set non_block
int flags = fcntl(listenfd, F_GETFL, 0);
if( -1 == fcntl(listenfd, F_SETFL, flags|O_NONBLOCK) )
{
printf("Set NONBLOCK for socket fd %d failed", listenfd);
exit(1);
}
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(8060);
bind(listenfd, (struct sockaddr*)&servaddr, sizeof(struct sockaddr));
listen(listenfd, 1024);
//***** socket *****
printf("start.\r\n");
for( i=0;i<3;i++)
{
pid=fork();
proccess_num=i;
if(pid == 0 || pid == -1)
{
printf(" not fork.\r\n");
break;
}
}
if (pid == -1)
{
printf("fork error.\r\n");
exit(1);
}
else if(pid == 0)
{
//child procces.
//********
printf("[%d] enter for...\r\n",proccess_num);
if (proccess_num == 1) // 1 write fifo
{
printf("[%d] init_fifo_write.\r\n",proccess_num);
res = init_fifo_write();
if (res == -1)
{
printf("init fifo write failed. exit.");
exit(EXIT_FAILURE);
}
WR_fifo_fd = res;
}
if (proccess_num == 2) // 2 read fifo
{
printf("[%d] init_fifo_read. \r\n",proccess_num);
res = init_fifo_read();
if (res == -1)
{
printf("init fifo read failed. exit.");
exit(EXIT_FAILURE);
}
RD_fifo_fd = res;
}
printf("[%d] child loop call accept() .\r\n",proccess_num);
for(;;)
{
//printf("[%d] sleep 2 sec.\r\n",proccess_num);
sleep(1);
//read fifo .
if (proccess_num == 2) // 2 read fifo
{
int clifd=-1;
//printf("[%d] fifo read.\r\n",proccess_num);
int shared_fd;
shared_fd = get_share_fd();
send_msg_to_client(shared_fd);
/*
res = read_sock_fd(RD_fifo_fd,&clifd);
if (res != true)
{
printf("[%d]read socket fd failed! \r\n",proccess_num);
}
else
{
printf("[%d]read socket fd succeed! fd:%d \r\n",proccess_num,clifd);
//send some data to client
printf("send some data to client! \r\n");
char buf_str[] = "This is second recieved Client!\n";
int ret = write(clifd, buf_str, sizeof(buf_str));
printf("write ret:%d. buf_str size:%d \r\n", ret,sizeof(buf_str));
printf("[%d] close client fd:%d \r\n",proccess_num,clifd);
time_t t;
time(&t);
printf("[%d]time: %ld\n",proccess_num,t);
close(clifd);
}*/
}
else if (proccess_num == 1) // 1 write fifo
{
clilen = sizeof(cliaddr);
//printf("[%d] child call accept() .\r\n",proccess_num);
if((connfd = accept(listenfd,(struct sockaddr*)&cliaddr, &clilen)) < 0)
{
//printf("[%d] accept failed. fd: %d.\r\n",proccess_num,connfd);
if(errno == EAGAIN)
{
//printf("[%d] accept EAGAIN.continue...\r\n",proccess_num);
continue;
}
else
{
printf("[%d] accept error.\r\n",proccess_num);
exit(1);
}
}
else
{
printf("[%d] accept succeed. fd:%d \r\n",proccess_num,connfd);
//sleep(10);
/*if (1) // 1 write fifo
{
printf("[%d] fifo write.\r\n",proccess_num);
//send socket fd to other proccess.
res = send_sock_fd(WR_fifo_fd, connfd);
if (res != true)
printf("[%d]send socket fd %d failed! sleep 10...\r\n",proccess_num,connfd);
else
printf("[%d]send socket fd %d succeed! sleep 10...\r\n",proccess_num,connfd);
sleep(10);
}*/
//send socket fd to other proccess!
int local_sockfd = s_create_usockfd();
//int client_fd = get_fd_to_send();
int client_fd = connfd;
s_send_fd(local_sockfd,client_fd);
printf("[%d]send socket fd[%d] to other proccess finish. close socket fd. \r\n",proccess_num,connfd);
close(connfd); //NOT close?
time_t t;
time(&t);
printf("[%d]time: %ld\n",proccess_num,t);
}
}
//********
//exit(0);
}
}
else
{
//parent.
printf("parent wait...\r\n");
while(1);
printf("parent exit.\r\n");
exit(0);
}
}
client的代码:
#include <stdio.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#define BUF_LEN 50
/************关于本文档********************************************
*filename: client.c
*purpose: 这是在Linux下用C语言写的一个简单sokcet客户端,用来向共享socket发送消息,以测试共享socket
进程接收消息情况。
使用方法:./client server-ip
更多开源软件,请访问http://fossd.net/?fromuid=32
*********************************************************************/
#include<time.h>
int main(int argc,char* argv[])
{
if (!argv[1])
{
printf(" useage: ./client [server ip] \r\n eixt. \r\n");
return -1;
}
int ret;
int fd;
int i,len;
struct sockaddr_in servaddr;
char buf[BUF_LEN];
fd_set writefds;
strcpy(buf,"hi, i am client\n");
fd = socket(AF_INET,SOCK_STREAM,0);
if(fd <= 0)
{
perror("socket");
return fd;
}
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(8060);
servaddr.sin_addr.s_addr = inet_addr(argv[1]);
printf("connect to server... \r\n");
ret = connect(fd,(struct sockaddr*)&servaddr,sizeof(servaddr));
if(ret != 0)
{
perror("connect");
return ret;
}
bzero(buf,BUF_LEN);
sprintf(buf,"%d hi,i came from client",i);
len = strlen(buf);
ret = write(fd,buf,BUF_LEN);
printf("write ret:%d \r\n",ret);
if (ret <= 0)
{
printf("write ret <= 0 \r\n");
}
char read_buf[1024]={0};
if(read(fd, read_buf, 1024) > 0)
{
printf("read data:%s \r\n", read_buf );
}
else
{
printf("read ret <= 0 \r\n");
}
printf("read finish. exit.\r\n");
time_t t;
time(&t);
printf("time: %ld\n",t);
/*
while(1)
{
int i,len,ret;
for(i = 0; i < 2000; i++)
{
bzero(buf,BUF_LEN);
sprintf(buf,"%d hi,i came from client",i);
len = strlen(buf);
ret = write(fd,buf,BUF_LEN);
}
sleep(3);
}
*/
}