基于数据报的实现

//

//上一个版本是基于连接的实现,今天改了一个基于数据报的实现

#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
#define LISTEN_QLEN 1024

int proccess_num=-1;
const char * share_path = "/home/907684/test/fd_send/share_fd";
const char * str_to_cli = "This is the second proccess speaking.\n";

//1,send socket fd
//2,recv socket fd
//3,client connect
//4,server listen -- accept
//5,get_share_fd() ?
//6,send msg to share_fd


void s_send_fd(int sockfd, int fd)
{
 struct sockaddr_un addr = {0}; 
 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 client fd[%d] to socket fd[%d]\n",fd, sockfd);

 rv = sendmsg(sockfd, &msg, 0) ;    
 printf("sendmsg return %d \r\n",rv);
 if(rv == -1)
 {
  if(errno == EAGAIN)
  {
   return;
  }
  else
  {
   //error
   printf("sendmsg error, file fd is %d\n", fd);    
      
   //close fd_to_send out side
   return;
  }
 }  
 else if( rv == 0 )
 {
  //close fd_to_send out side
  return;  
  
 } 
   
 printf("send fd[%d] to shared file finish.\r\n", fd);
 //close fd_to_send out side

 

//************************ recv socket fd
//client socket()--name socket--connect()
//server socket()--name socket--bind()--listen() ==> accept()

int cli_connect_usockfd(const char* path)
/* client creat unix domain socket. failed return -1. */
{
  if( path == NULL )
  {
   printf("[%d]path error. \r\n",proccess_num);
   return -1;
   }
   
    struct sockaddr_un addr = {0};
    int fd;
   
    if( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
    {
     printf("[%d]creat unix domain socket failed. \r\n",proccess_num);
     return -1;
    }
 
    addr.sun_family = AF_UNIX;  //mostly, PF_UNIX=AF_UNIX
    strcpy(addr.sun_path, path); 
 
    if( connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1 ){
      if(errno != EINPROGRESS) //for non-block
      {
         printf("[%d] connect unix domain socket failed, %d, %s\n",proccess_num, errno, strerror(errno));
         return -1;
        }
    }

    printf("[%d] connect unix domain socket ok.\n", proccess_num);
 
    return fd;
}

//client socket()--name socket--connect()
//server socket()--name socket--bind()--listen() ==> accept()
int serv_listen_usockfd(const char* path)
/* server creat unix domain socket. failed return -1. */
{
    struct sockaddr_un addr = {0};
    int fd;
   
    if( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
    {
     printf("[%d]creat unix domain socket failed. \r\n",proccess_num);
     return -1;
     }
    unlink(path); //in case it already exists.
 
    addr.sun_family = AF_UNIX;  //mostly, PF_UNIX=AF_UNIX
    strcpy(addr.sun_path, path); 
 
    if( bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1 ){
        printf("[%d] bind unix domain socket failed, %d, %s\n",proccess_num, errno, strerror(errno));
        return -1;
    }
    printf("[%d] bind unix domain socket ok.\n", proccess_num);
   
    if( listen(fd, LISTEN_QLEN) == -1 )
    {
     //close fd???????????????????????????????????????????????
     
     printf("[%d] listen unix domain socket error.error:%d,msg:%s. \n", proccess_num, errno, strerror(errno));
     return -1;
     }
    printf("[%d] listen unix domain socket ok.\n", proccess_num); 
   
    return fd;
}

static int serv_accept_usockfd(int listen_fd)
 /* server accept unix domain socket. failed return -1. */
{
    struct sockaddr_un addr = {0};
    socklen_t len= sizeof(addr);
   
    return accept(listen_fd,(struct sockaddr*)&addr,&len); //fd,Eagain,other  --3 case ??????????????????????
   
    /*
    int report = CReportEngin::m_ReportListen.Accept();
  if(report > 0)
  {
   if(false == m_ReportEngin->AddJob(report))
   {
    LOG_ERROR("[CACHESERVER] Failed to accept report.");
    close(report);
   }
  }
  else if(errno == EAGAIN)
   return;
  else
  {
   LOG_ERROR("[CACHESERVER] Failed to accept report." << strerror(errno));

   return;
  }
    */
}
 
int r_recv_fd(int fd)
/* recv internet socket fd. return value >0:succeed ,0:need retry, -1:failed. */
{
    struct msghdr msg = {0};
    int rv = 0;
    int cfd = -1,client_fd=-1;
    char ccmsg[CMSG_SPACE(sizeof(cfd))];
    struct cmsghdr* cmptr;
 
    msg.msg_control = ccmsg;
    msg.msg_controllen = sizeof(ccmsg);
 
    rv = recvmsg(fd, &msg, 0);
  if(rv == -1)
  {
   if(errno == EAGAIN)
   {
    return 0;
   }
   else
   {
    //error
    printf("sendmsg error, file fd is %d\n", fd);    
       
    //close fd ????????????????????????????? sockfd do not close!!!
    return -1;
   }
  }  
  else if( rv == 0 )
  {
   //error
   //close fd ????????????????????????????? sockfd do not close!!!
   return -1;  
   
  }    
  
    cmptr = CMSG_FIRSTHDR(&msg);
  if((cmptr != NULL) && (cmptr->cmsg_len == CMSG_LEN(sizeof(int))))
  {
   if(cmptr->cmsg_level != SOL_SOCKET)
   {
    printf("control level != SOL_SOCKET/n");
    return -1;  
   }
   if(cmptr->cmsg_type != SCM_RIGHTS)
   {
    printf("control type != SCM_RIGHTS/n");
    return -1;  
   }
   
   client_fd = *((int*)CMSG_DATA(cmptr));
  }
  else
  {
   if(cmptr == NULL)
    printf("null cmptr, fd not passed./n");
   else
    printf("message len[%d] if incorrect./n", cmptr->cmsg_len);
   
   return -1;  
  }
    printf("[%d]recieved client socket fd[%d].\n",proccess_num,client_fd);

    return client_fd;
}


void send_msg_to_client(int cfd, const char* str)
{   
    printf("[%d]write string to recieved file fd[%d]. string[%s]\r\n",proccess_num, cfd,str);
   
    int rv = write(cfd, str, strlen(str));
  if(rv == -1)
  {
   if(errno == EAGAIN)
   {
    return;
   }
   else
   {
    //error
    printf("[%d]sendmsg error, fd is %d\n",proccess_num, cfd);    
       
    //close fd ????????????????????????????? sockfd do not close!!!
    return;
   }
  }
  else if( rv == 0 )
  {
   //error
   //close fd ?????????????????????
   }
  else
  {
   printf("[%d]finish send msg to client.",proccess_num);   
   //close fd ?????????????????????
  }
  
}

//************************ 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;
 int u_listen_fd, u_sock_fd2 ;
 
 //***** socket *****
 int s_listen_f,s_conn_fd;
 socklen_t clilen;
 struct sockaddr_in cliaddr,servaddr;
 
 s_listen_f = socket(AF_INET,SOCK_STREAM,0);
 
 //set non_block
 int flags = fcntl(s_listen_f, F_GETFL, 0);
 if( -1 == fcntl(s_listen_f, F_SETFL, flags|O_NONBLOCK) )
 {
  printf("Set NONBLOCK for socket fd %d failed", s_listen_f);
  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(s_listen_f, (struct sockaddr*)&servaddr, sizeof(struct sockaddr));
 listen(s_listen_f, 1024);
 //***** socket *****
 
 printf("start 2.\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);*/
   u_sock_fd2 = cli_connect_usockfd(share_path); //inti unix domain socket client    
   if( u_sock_fd2 == -1 )
   {
    //error ???
    return -1;
   }
  }
  
  if (proccess_num == 2) // 2 read fifo
  {
   /*printf("[%d] init_fifo_read. \r\n",proccess_num);*/
   //init listen unix domain socket.
   u_listen_fd = serv_listen_usockfd(share_path);
   if(u_listen_fd == -1)
   {
    printf("serv_listen_usockfd return %d ,errno:%d, msg:%s . \r\n", u_listen_fd, errno, strerror(errno) );
    return -1;
   }
  }
  
  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 Unix domain socket
    {
     int u_fd=-1;
     //printf("[%d] fifo read.\r\n",proccess_num);
     int shared_fd=-1;
      
       // 1,put in unix domain socket listen main loop     
       u_fd = serv_accept_usockfd(u_listen_fd);
       printf("accept return %d \r\n", u_fd);
       if(u_fd == -1)
       {
        if(errno == EAGAIN)
        {
         continue;
        }
        else
        {
         printf("accept error %d \r\n",errno);
         return -1;
        }
       }          
       // 2,add u_fd to epoll
       
       // 3,when u_fd readable
       shared_fd = r_recv_fd(u_fd);    // return value ??????????????????????????????  
       if(shared_fd == 0)
       {
        printf("[%d] recv no fd, retry later. \r\n", proccess_num);
        return;
       }
       else if( shared_fd == -1 )
       {
        printf("[%d] recv fd failed. \r\n", proccess_num);
        //NOT close u_fd ??????
        return;
       }
      
       // 4,add shared_fd to epoll
      
       // 3,when shared_fd writeable        
     send_msg_to_client(shared_fd, str_to_cli);
     close(shared_fd);
    }
    else if (proccess_num == 1) // 1 write Unix domain socket
    {
     clilen = sizeof(cliaddr);
     //printf("[%d] child call accept() .\r\n",proccess_num);
     
     // 1, put in internet socket listen main loop     
     if((s_conn_fd = accept(s_listen_f,(struct sockaddr*)&cliaddr, &clilen)) < 0)
     {
      //printf("[%d] accept failed. fd: %d.\r\n",proccess_num,s_conn_fd);
      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,s_conn_fd);  
      
      // 2,(when init unix domain socket)add u_sock_fd2 to epoll
      
      // 3,when u_sock_fd2 is writeable
      //send socket fd to other proccess!
      s_send_fd(u_sock_fd2,s_conn_fd);        
      
      printf("[%d]send socket fd[%d] to other proccess finish. close socket fd. \r\n",proccess_num,s_conn_fd);
      close(s_conn_fd); 
     }
    }
  }
 }
 else
 {
  //parent.
  printf("parent wait...\r\n");
  while(1);
  printf("parent exit.\r\n");
  exit(0);
  }
 
 }

posted @ 2013-08-05 21:09  反光镜的博客  阅读(336)  评论(0编辑  收藏  举报