Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2149097
  • 博文数量: 361
  • 博客积分: 10828
  • 博客等级: 上将
  • 技术积分: 4161
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-20 14:34
文章分类

全部博文(361)

文章存档

2011年(132)

2010年(229)

分类: C/C++

2010-03-05 19:30:56

 
在一般的socket实现的时候,通常是用参数的形式,将文件描述符(FD)传到子进程或者直接传到read()汉书中。
不过如果想以Socket的形式,来传送FD的话,那就要用到sendmsg和recvmsg函数了。关键点,FD的值要通过msg.msg_control来传递的,千万别写到传输用的buff里面,那样做只是简单的传值,没有任何意义的。
/*
-------------------------------------------------
            server
-------------------------------------------------
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define PORT1 (u_short)11005
#define PORT2 (u_short)11002
/*
-------------------------------------------------
            グローバル変数
-------------------------------------------------
*/
struct  hostent *myhost;
char    hostname[257];
char    buff[257];
struct  sockaddr_in me;
struct  sockaddr_in aite;
int     sockfd;
int fd = 0;
int s_retry_counter;
int ret;
int status;
int     pid;
int aiteaddrlen;
fd_set l_fds;
 
int sendmsg_fd;
int recvmsg_fd;
int rcv_proc();
/*-------------------------------------------------
           メインルーチン
-------------------------------------------------
*/
int main () {
 int l_rtn;
 struct cmsghdr *l_cmsg;
 struct msghdr msg;
    struct iovec iov[1];
 int send_buf = 1;
 int l_length;
 char cms_data[sizeof(struct cmsghdr) + sizeof(int)];
 int l_fd_pair[2];              
    if(socketpair(PF_UNIX, SOCK_STREAM, 0, l_fd_pair) != 0)
    {
     fprintf(stderr,"Create socketpair failed.\n");
    }
 pid = fork();
 switch(pid)
 {
  case -1: //エラー
   // 親側のソケットをクローズする
   fprintf(stderr,"fork() failled.\n");
   break;
  case 0:  //子プロセス側
   close(l_fd_pair[0]);
   recvmsg_fd = l_fd_pair[1];
   rcv_proc();
   break;
  default: //親プロセス側
   close(l_fd_pair[1]);
   sendmsg_fd = l_fd_pair[0];
   break;
 }
 /*ソケットを作成*/
 if ((sockfd = socket(AF_INET, SOCK_STREAM , 0)) < 0 ) {
  fprintf(stderr,"Socket for server failed.\n");
  return -1;
 }
 /*自ホスト名の取得*/
 bzero(hostname,257);
 gethostname(hostname,256);
 /*自IPアドレスを取得*/
 if((myhost = gethostbyname(hostname)) == NULL) {
  fprintf(stderr,"bad hostname!\n");
  return -1;
 }
 /*自ホスト情報を構造体にセット*/
 bzero((char *)&me,sizeof(me));
 me.sin_family  = AF_INET;
 me.sin_port    = htons(PORT1);
 bcopy(myhost->h_addr, (char *)&me.sin_addr, myhost->h_length);
 
 /*BIND*/
  l_rtn = bind ( sockfd, (struct sockaddr *)&me, sizeof(me));
 if( l_rtn == -1)
 {
  fprintf(stderr, "Server could not bind.\n");
  return -1;
 }
 printf("Successfully bound in PORT1 %u.\n",PORT1);
 /*listen*/
 if ( (listen ( sockfd , 5)) == -1) {
  fprintf(stderr, "Listen failed.\n");
  return -1;
   }
/*
-------------------------------------------------
  ACCEPT
-------------------------------------------------
*/
 s_retry_counter=0;
 fd = 0;
 while(1) {
/*  FD_ZERO( &l_fds );
  FD_SET(sockfd, &l_fds );
  l_rtn = select( sockfd+1, &l_fds, NULL, NULL, NULL);
  if(l_rtn == -1)
  {
   fprintf(stderr,"Select error !!\n");
   return -1;
  }
 
  if( FD_ISSET(sockfd, &l_fds) )
   {
*/
   /* acceptを試みる */
   aiteaddrlen = sizeof(aite);
   fd = accept( sockfd, ( struct sockaddr * )&aite , &aiteaddrlen);
   /*  accept失敗  */
   if (fd == -1) {
    fprintf(stderr,"Accept failed.\n");
    return -1;
   }
   printf("accept fd : %d\n", fd);
//   send_buf = fd;
 
    l_length = sizeof(struct cmsghdr) + sizeof(int);
    l_cmsg = (struct cmsghdr*)cms_data;
   l_cmsg->cmsg_level = SOL_SOCKET;
   l_cmsg->cmsg_type  = SCM_RIGHTS;
   l_cmsg->cmsg_len   = l_length;
   
         bzero(&msg, sizeof(msg));
         msg.msg_name = NULL;        /* attention this is a pointer to void* type */
         msg.msg_namelen = 0;
         iov[0].iov_base = &send_buf;
         iov[0].iov_len = sizeof(send_buf);
         msg.msg_iov = iov;
         msg.msg_iovlen = 1;
   msg.msg_control    = (caddr_t)l_cmsg;
   msg.msg_controllen = l_length;
    *(int *)CMSG_DATA(l_cmsg) = fd;
    printf("sendmsg begin. sendmsg_fd = %d\n", sendmsg_fd);
   l_rtn = sendmsg( sendmsg_fd, &msg, 0 );
   if(l_rtn == -1 )
   {
    fprintf(stderr,"Sendmsg failed.  errno : %s\n",strerror(errno));
    return -1;
   }
    printf("Sendmsg Success!\n");
 // }
 
 }
 return 0;
}
/*
=================================================
        子プロセス (s ソケット)
        正常終了:0   異常終了:-1
=================================================
*/
int rcv_proc()
{
 int l_rtn;
 int cnt;
 int buff_size;
 struct msghdr msg;
    struct iovec iov[1];
 struct cmsghdr *cmsg_hdr;
 int cmsg_len;
    int recv_buf;
 int rcv_fd = 0;
 fd_set l_fds;
// fd_set readok;
 int width;
 char recv_data[sizeof(struct cmsghdr) + sizeof(int)];
 cmsg_hdr = (struct cmsghdr*)recv_data;
 cmsg_len = sizeof(struct cmsghdr) + sizeof(int);
 printf("rcr_proc begin.\n");
 
 for(;;)
 {       bzero(&msg, sizeof(msg));
         msg.msg_name = NULL;        /* attention this is a pointer to void* type */
         msg.msg_namelen = 0;
         iov[0].iov_base = &recv_buf;
         iov[0].iov_len = sizeof(recv_buf);
         msg.msg_iov = iov;
         msg.msg_iovlen = 1;
      msg.msg_control    = (caddr_t)cmsg_hdr;
      msg.msg_controllen = cmsg_len;
         printf("recvmsg begin. recvmsg_fd = %d\n", recvmsg_fd);
         l_rtn = recvmsg( recvmsg_fd, &msg, 0);
   if(l_rtn == -1 )
   {
    fprintf(stderr,"Recvmsg failed.  errno : %s\n", strerror(errno));
    return -1;
   }
    printf("Recvmsg Success!\n");
   rcv_fd =  *((int *)CMSG_DATA(cmsg_hdr));
         FD_ZERO(&l_fds);
   FD_SET(rcv_fd, &l_fds);
   width = rcv_fd + 1;
/*
    readok = l_fds;
          l_rtn = select(width, &readok, NULL, NULL, NULL);
          if(l_rtn == -1){
           fprintf(stderr,"Selete failed.  errno : %s\n", strerror(errno));
           //return -1;
          }
          if( FD_ISSET(rcv_fd, (fd_set *)&readok) )
          {
           */
           printf("read fd : %d\n", rcv_fd);
           printf("read() begin.\n");
           bzero(buff,257);
           buff_size = read ( rcv_fd, buff, 256 );
           printf("buff_size : %d\n", buff_size);
    
           if(buff_size == -1){
            fprintf(stderr, "Read failed. errno : %s\n", strerror(errno));
            return -1;
           }
           printf("Received buffer : ");
           for (cnt=0; cnt< buff_size; cnt++) {
      putchar(buff[cnt]);
     }
   // }
 }
 return 1;
}
/*
-------------------------------------------------
            client
-------------------------------------------------
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define PORT (u_short)11005
/*
-------------------------------------------------
            グローバル変数
-------------------------------------------------
*/
char    hostname[257];
char    buff[257];
struct  hostent *connect_host;
struct  sockaddr_in desthost;
int     s_listen;
int s;
int s_retry_counter;
int ret;
int status;
int     pid;
int portno;
/*
-------------------------------------------------
           メインルーチン
-------------------------------------------------
*/
int main () {
 /*接続先ホスト名設定*/
 bzero(hostname,257);
 strcpy(hostname,"127.0.0.1");
 /*接続先IPアドレス取得*/
 if((connect_host = gethostbyname(hostname)) == NULL) {
  fprintf(stderr,"bad hostname!\n");
  return -1;
 }
 /*接続先情報をソケット型構造体にセット*/
 bzero((char *)&desthost,sizeof(desthost));
 desthost.sin_family  = AF_INET;
 desthost.sin_port    = htons(PORT);
 bcopy(connect_host->h_addr, (char *)&desthost.sin_addr, connect_host->h_length);
 /*ソケットを作成*/
 if ((s_listen = socket(AF_INET, SOCK_STREAM,0)) < 0 ) {
  fprintf(stderr,"Socket for client failed.\n");
  return -1;
 }
 /*コネクト*/
 if (connect(s_listen, ( struct sockaddr * )&desthost , sizeof(desthost) ) == -1) {
  fprintf(stderr,"Connect failed.\n");
  return -1;
 }
 /*文字列送信*/
 bzero(buff,257);
 strcpy(buff,"Test ABC.\n");
 if ( write(s_listen, buff, 256 ) == -1 ) {
  fprintf(stderr,"Write failed.\n");
  return -1;
 }
 /*ソケット切断*/
 close(s_listen);
 /*終了*/
 return 0;
}
 
阅读(1563) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~