Unix进程间SOCKET句柄传递-进程池应用

来源:互联网 发布:百度音乐播放器 mac 编辑:程序博客网 时间:2024/05/06 21:00

/* test_fdpass.c */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

#include <sys/socket.h> /* for socketpair */

#define MY_LOGO         "-- Tony Bai"

static int send_fd(int fd, int fd_to_send)
{
        struct iovec    iov[1];
        struct msghdr   msg;
        char            buf[1];

        if (fd_to_send >= 0) {
                msg.msg_accrights       = (caddr_t)&fd_to_send;
                msg.msg_accrightslen    = sizeof(int);
        } else {
                msg.msg_accrights       = (caddr_t)NULL;
                msg.msg_accrightslen    = 0;
        }

        msg.msg_name    = NULL;
        msg.msg_namelen = 0;

        iov[0].iov_base = buf;
        iov[0].iov_len  = 1;
        msg.msg_iov     = iov;
        msg.msg_iovlen  = 1;

        if(sendmsg(fd, &msg, 0) < 0) {
                printf("sendmsg error, errno is %d/n", errno);
                return errno;
        }

        return 0;
}

static int recv_fd(int fd, int *fd_to_recv)
{
        struct iovec    iov[1];
        struct msghdr   msg;
        char            buf[1];

        msg.msg_accrights       = (caddr_t)fd_to_recv;
        msg.msg_accrightslen    = sizeof(int);

        msg.msg_name    = NULL;
        msg.msg_namelen = 0;

        iov[0].iov_base = buf;
        iov[0].iov_len  = 1;
        msg.msg_iov     = iov;
        msg.msg_iovlen  = 1;

        if (recvmsg(fd, &msg, 0) < 0) {
                return errno;
        }

        if(msg.msg_accrightslen != sizeof(int)) {
                *fd_to_recv = -1;
        }

        return 0;
}

int x_sock_set_block(int sock, int on)
{
        int             val;
        int             rv;

        val = fcntl(sock, F_GETFL, 0);
        if (on) {
                rv = fcntl(sock, F_SETFL, ~O_NONBLOCK&val);
        } else {
                rv = fcntl(sock, F_SETFL, O_NONBLOCK|val);
        }

        if (rv) {
                return errno;
        }

        return 0;
}

int main() {
        pid_t   pid;
        int     sockpair[2];
        int     rv;
        char    fname[256];
        int     fd;

        rv = socketpair(AF_UNIX, SOCK_STREAM, 0, sockpair);
        if (rv < 0) {
                printf("Call socketpair error, errno is %d/n", errno);
                return errno;
        }

        pid = fork();
        if (pid == 0) {
                /* in child */
                close(sockpair[1]);

                for ( ; ; ) {
                        rv = x_sock_set_block(sockpair[0], 1);
                        if (rv != 0) {
                                printf("[CHILD]: x_sock_set_block error, errno is %d/n", rv);
                                break;
                        }

                        rv = recv_fd(sockpair[0], &fd);
                        if (rv < 0) {
                                printf("[CHILD]: recv_fd error, errno is %d/n", rv);
                                break;
                        }

                        if (fd < 0) {
                                printf("[CHILD]: child process exit normally!/n");
                                break;
                        }

                       /* 处理fd描述符对应的文件 */
                        rv = write(fd, MY_LOGO, strlen(MY_LOGO));
                        if (rv < 0) {
                                printf("[CHILD]: write error, errno is %d/n", rv);
                        } else {
                                printf("[CHILD]: append logo successfully/n");
                        }
                        close(fd);
                }

                exit(0);
        }

        /* in parent */
        for ( ; ; ) {
                memset(fname, 0, sizeof(fname));
                printf("[PARENT]: please enter filename:/n");
                scanf("%s", fname);

                if (strcmp(fname, "exit") == 0) {
                        rv = send_fd(sockpair[1], -1);
                        if (rv < 0) {
                                printf("[PARENT]: send_fd error, errno is %d/n", rv);
                        }
                        break;
                }

                fd = open(fname, O_RDWR | O_APPEND);
                if (fd < 0) {
                        if (errno == ENOENT) {
                                printf("[PARENT]: can't find file '%s'/n", fname);
                                continue;
                        }
                        printf("[PARENT]: open file error, errno is %d/n", errno);
                }

                rv = send_fd(sockpair[1], fd);
                if (rv != 0) {
                        printf("[PARENT]: send_fd error, errno is %d/n", rv);
                }

                close(fd);
        }

        wait(NULL);
        return 0;
}

=================================================================
Under Windows
int   CSocketFunc::socketpair(int   family,   int   socktype,   int   protocol,   int   fd[2])  
  {  
  #ifndef   WIN32   //uninx/linux平台  
  return   ::socketpair(AF_LOCAL,   socktype,   0,   fd);  
  #else     //WIN32   平台  
  int   listener;  
  struct   sockaddr_in   sockAdd     =   {0};  
  struct   sockaddr_in   sockAdd2   =   {0};  
  int   socklen   =   sizeof(sockAdd2);  
  long   ltemp   =1;  
   
  fd[0]   =   fd[1]   =   listener   =   -1;  
   
  if   ((listener   =   (int)socket(AF_INET,   SOCK_STREAM,   IPPROTO_TCP))   ==   -1)  
  goto   FAILED;  
  memset(&sockAdd2,   0,   sizeof(sockAdd2));  
  //sockAdd2.sin_addr.s_addr   =   ::htonl(INADDR_LOOPBACK);  
  sockAdd2.sin_family   =   family;  
   
  if(bind(listener,   (struct   sockaddr   *)&sockAdd2,   sizeof(sockAdd2))   !=0)  
                  goto   FAILED;      
   
  if   (listen(listener,   1)   !=   0)    
  goto   FAILED;  
   
  if   (::getsockname(listener,   (struct   sockaddr   *)&sockAdd,   &socklen)   !=   0)    
  goto   FAILED;  
   
  if   ((fd[1]   =   (int)socket(AF_INET,   SOCK_STREAM,   IPPROTO_TCP))   ==   -1)    
  goto   FAILED;  
   
  //设置为非阻塞模式  
  ltemp   =1;  
  ioctlsocket(fd[1],   FIONBIO,   (u_long   *)&ltemp);  
   
  sockAdd.sin_addr.s_addr   =   ::htonl(INADDR_LOOPBACK);  
   
  if   (connect(fd[1],   (struct   sockaddr   *)&sockAdd,   sizeof(sockAdd))   ==   -1)    
  {  
  if   ((ltemp   =   WSAGetLastError())   !=   WSAEWOULDBLOCK  
  &&   ltemp   !=   WSAEINPROGRESS   )  
  goto   FAILED;  
  }  
   
  if   ((fd[0]   =(int)accept(listener,   (struct   sockaddr   *)&sockAdd2,   &socklen))   ==   -1)  
  goto   FAILED;  
           
  //设置回为阻塞模式  
  ltemp   =0;  
  ioctlsocket(fd[1],   FIONBIO,   (u_long   *)&ltemp);  
           
  closesocket(listener);  
   
  //   all   OK!    
  return   0;  
   
  FAILED:  
  if   (fd[0]   !=   -1)   closesocket(fd[0]);  
  if   (fd[1]   !=   -1)   closesocket(fd[1]);  
  if   (listener   !=   -1)   closesocket(listener);  
  return   -1;  
   
  #endif   //   WIN32  
  }  
原创粉丝点击