c++版本的句柄发送封装


#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>
///////////////////////////////


/********************************* head files **************************************/
//#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>

#include <vector>
#include <iostream>
#include <string>
//#define NULL 0
#include <stdlib.h>
#include <time.h>
 
using namespace std;
/**************************** Function declaration *********************************/
/* class CUnixSockBase */
class CUnixSockBase
{
protected:
/* 'm_SharePathList' include every proccess's shared path
For example:
m_SharePathList[0] is proccess_0's shared path
m_SharePathList[1] is proccess_1's shared path ...
*/
//vector<string> m_SharePathList;

/* 'm_ProccessNum' is the number of the owner proccess.
For example:
proccess_0's m_ProccessNum is 0
proccess_1's m_ProccessNum is 1
*/
static int m_ProccessNum;

struct sockaddr_un addr; 
int m_uSockFd;

public:
CUnixSockBase(){ }
~CUnixSockBase(){ }
int Init(const char* path); //return usock fd
virtual int CreateUnixSock(const char* path)=0; 
virtual int SendFd(int sockfd, int fd)=0; 
virtual int RecvFd(int fd)=0;
};


/* class CSendUnixSock */
class CSendUnixSock:public CUnixSockBase
{
public:
CSendUnixSock(){ }
~CSendUnixSock(){ }

int CreateUnixSock(const char* path); 
int SendFd(int sockfd, int fd); 
int RecvFd(int fd){}
};


/* class CSendUnixSock */
class CRecvUnixSock:public CUnixSockBase
{
protected:
//
public:
 CRecvUnixSock(){ }
 ~CRecvUnixSock(){ }
 int CreateUnixSock(const char* path); 
 int RecvFd(int fd);
 int SendFd(int sockfd, int fd){}
};


/**************************** Function realize *********************************/
/* class CUnixSockBase */
//vector<string> CServerMgr::m_Programs;

int CUnixSockBase::Init(const char* path)
{
 printf("input path name :%s. \r\n",path);
 if( path == NULL )
 {
  printf("input path name error. \r\n");
  return -1;
 }
 
 m_uSockFd = CreateUnixSock(path);   
 if(m_uSockFd == -1)
 {
  printf("serv_create_usockfd error. \r\n");
  return -1;
 }
 return 0;
}


/* class CSendUnixSock */

int CSendUnixSock::CreateUnixSock(const char* path)
{
 if( path == NULL )
 {
  printf("input path name error. \r\n");
  return -1;
 }
 
 //struct sockaddr_un addr = {0};
 int fd;
 
 addr.sun_family = AF_UNIX;  //mostly, PF_UNIX=AF_UNIX
 strcpy(addr.sun_path, path); 
 
 if( (fd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
 {
  printf("creat unix domain socket failed. \r\n");
  return -1;
 }
 
 printf("connect unix domain socket ok.\n");
 return fd;
}


int CSendUnixSock::SendFd(int sockfd, int fd)
{
 /* remember close fd(fd to send) after call SendFd()! */
 
 //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("send 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 1;
  }
  else
  {
   //error
   printf("sendmsg error, ret is %d\n", fd);          
   //close fd_to_send out side
   return -1;
  }
 }  
 /*else if( rv == 0 )
 {
 //close fd_to_send out side
 printf("sendmsg error, ret is %d\n", rv);
 return -1; 
 
 }  */
 
 printf("send fd[%d] to shared file finish.\r\n", fd);
 return 0;
}

 


/* class CRecvUnixSock */

int CRecvUnixSock::CreateUnixSock(const char* path)
/* server creat unix domain socket. failed return -1. */
{
 //struct sockaddr_un addr = {0};
 int fd;
 
 unlink(path); //in case it already exists.
 
 if( (fd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
 {
  printf("creat unix domain socket failed. \r\n");
  return -1;
 }
 
 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(" bind unix domain socket failed, %d, %s\n", errno, strerror(errno));
  return -1;
 }
 printf("bind unix domain socket ok.\n");
 
 return fd;
}


int CRecvUnixSock::RecvFd(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,clientFd=-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);                
   return -1;
  }
 }  
 /*
 else if( rv == 0 )
 {
 //error
 printf("sendmsg error, file fd is %d\n", fd);  
 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; 
  }
  
  clientFd = *((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("recieved client socket fd[%d].\n",clientFd);
 
 return clientFd;
}

/**************************** End *********************************/


using namespace std;
int main(int argc, char* argv[])
{
 //***** socket *****
  int s_listen_f;
  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 *****

 
 
 
 
 
 //string sharePathBase("/home/") ;
 string basePath("shareFile_");
 //string basePath;
 int res = -1,i=0;
 int CPU_Num = 5, proccess_num = 2;
 char* tmpStr= new char[64];
 //fork...
 
 //in child proccess...
 
 // 1,connect server side share file
 vector<CSendUnixSock *> m_cliAddrList(CPU_Num,NULL);
 
 for(i=0;i<CPU_Num;i++)
 {
  if(i != proccess_num)
  {
   CSendUnixSock *sendSock = new CSendUnixSock;   
   //ltoa(i,tmpStr,10);
   sprintf(tmpStr, "%d",i);
   
   string tmp(basePath.c_str());
   res = sendSock->Init((tmp.append(tmpStr)).c_str());
   if(res == -1)
   {
    //error
    printf("sendSock init error");
    return -1;
   }
   else
   {
    m_cliAddrList[i]=sendSock;
   }
  }
 }
 
 //print
 for(i=0;i<CPU_Num;i++)
 {
  cout << "pos:"<<i<<" sendSock ptr:"<< m_cliAddrList[i]<< endl;
 }   
 
 // 2,listen my own share file
 CRecvUnixSock *recvSock = new CRecvUnixSock;   
 
 sprintf(tmpStr, "%d",proccess_num);
 string tmp(basePath.c_str());

 res = recvSock->Init((tmp.append(tmpStr)).c_str());
 if(res == -1)
 {
  //error
  printf("recvSock init error");
  return -1;
 }
   
 // 3,accept internet socket
 int s_conn_fd = -1,cli_usock_fd = -1;
 for(;;)
 {
      sleep(2);  
      printf("[%d] call accept .... \r\n",proccess_num);
  
     socklen_t clilen = sizeof(cliaddr);
     // 1, put in internet socket listen main loop    
     if((s_conn_fd = accept(s_listen_f,(struct sockaddr*)&cliaddr, &clilen)) < 0)
     {
      if(errno == EAGAIN)
      {
       continue;
      }
      else
      {
       printf("[%d] accept error.\r\n",proccess_num);
       return -1;
      }
     }        
         
      printf("[%d] accept succeed. fd:%d \r\n",proccess_num,s_conn_fd);       
      // 2,(when init unix domain socket)add u_cli_fd to epoll      
      // 3,when u_cli_fd is writeable
    
      // 4,send internet socket fd to next proccess
      int nextProcNum = (proccess_num+1)%CPU_Num;
      
      CSendUnixSock *tmp = m_cliAddrList[nextProcNum];
      //int cli_usock_fd = tmp->m_uSockFd;
      int cli_usock_fd = -100;
      res = tmp->SendFd(cli_usock_fd, s_conn_fd);   
      printf("[%d] send internet socket fd[%d] to proccess[%d] usock fd[%d] \r\n",proccess_num,s_conn_fd,proccess_num+1, cli_usock_fd);        
      if(res <= 0)
      {
       printf("[%d]close socket internet fd[%d]. \r\n",proccess_num,s_conn_fd); 
       close(s_conn_fd); 
      }         
    
      printf("[%d]send socket fd[%d] to other proccess finish. \r\n",proccess_num,s_conn_fd); 
  }
 
 
 
 return 0;

}

posted @ 2013-08-06 18:15  反光镜的博客  阅读(332)  评论(0编辑  收藏  举报