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);
   }
  */


}

 

 

 

posted @ 2013-08-03 19:13  反光镜的博客  阅读(567)  评论(0编辑  收藏  举报