How to transfer a socket between process

26 篇文章 0 订阅

This is a sample program to transfer a socket from one process to another process using unix domain socket.


Content

  • ListenerThis is a TCP listener server, which listen on a well-known port, to accept client's request. Whenever a client's connection request is coming, it launch a UpperServer process, and pass the FD which is used to communicate with client to UpperServer, so that the Client and UpperServer can communicate later without the Listener any more.
  • UpperServerThis is a Upper echo server, its function is return the uppercase string back to client.
  • ClientThis is client process

Usage

  • ./Listener 12345Launch Listener server on port 12345
  • ./Client 12345 UpperServerLaunch a client to connect to port 12345, and it will request Listener server to launch UpperServer as worker server.
  • Loop communicate between Client and UpperServer; such as:Please enter the message(quit for quit): aaa
    Receive message from server: AAA
    Please enter the message(quit for quit): bbb
    Receive message from server: BBB
    Please enter the message(quit for quit): ccc
    Receive message from server: CCC
    Please enter the message(quit for quit): 

Codes

Listener.c

/**

  * Usage: Listener PORT

  * for example, Listener 12345

  */

int main(int argc, char *argv[])

{

    int userListenSock;                    /* Socket descriptor for server */

    int workListenSock;                    /* Socket descriptor for server */

    int userClientSock;                    /* Socket descriptor for client */

    int workClientSock;                    /* Socket descriptor for client */


    struct sockaddr_in userListenAddr; /* Local address */

    struct sockaddr_un workListenAddr; /* Local address */


    struct sockaddr_in userClientAddr; /* Client address */

    struct sockaddr_un workClientAddr; /* Client address */


    socklen_t size;            /* Length of client address data structure */


    char workerCMD[256];

    unsigned char buffer[256];

    int n;


    assert (argc == 2);


    /* Create socket for client connections */

    userListenSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));

     

    memset(&userListenAddr, 0, sizeof(userListenAddr));   /* Zero out structure */

    userListenAddr.sin_family = AF_INET;                /* Internet address family */

    userListenAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */

   

    userListenAddr.sin_port = htons(atoi(argv[1]));      /* Local port */

    bind(userListenSock, (struct sockaddr *) &userListenAddr, sizeof(userListenAddr));

    listen(userListenSock, 1);



    /* Create socket for worker connections */

    workListenSock = socket(AF_UNIX, SOCK_STREAM, 0));


    memset(&workListenAddr, 0, sizeof(workListenAddr));   /* Zero out structure */

    workListenAddr.sun_family = AF_UNIX;                /* Internet address family */

    strcpy(workListenAddr.sun_path, "./socketfile" );

    unlink("./socketfile");


    bind(workListenSock, (struct sockaddr *) &workListenAddr, sizeof(workListenAddr));


    listen(workListenSock, 1);


    for (;;) /* Run forever */

    {

        /* Set the size of the in-out parameter */

        size = sizeof(userClientAddr);


        /* Wait for a client to connect */

        printf("waiting client connection ...\n");

        userClientSock = accept(userListenSock, (struct sockaddr *) &userClientAddr, &size));

           



        printf("waiting client's request for a worker ...");

        n = read(userClientSock, buffer, 255));

        buffer[n]='\0';

        printf("(%s)\n", buffer);

        sprintf(workerCMD, "./%s", buffer);

        printf("launch worker : %s\n",workerCMD);

        popen(workerCMD, "r");    // lazy doing, popen is used here


        /* Wait for a work process to connect */

        printf("waiting worker to connect ...\n");

        workClientSock = accept(workListenSock, (struct sockaddr *) &workListenAddr, &size));


        printf("waiting READY message from worker ...\n");

        n = read(workClientSock, buffer, 255));

        if (n < 0 || strncmp((const char *)buffer, READY, strlen(READY)) != 0) {

           printf("read() return %d=[%s]\n", n, buffer);

           Error("read() data incorrect");

        }


    buffer[n]='\0';

        printf("pass FD(%d) to worker(%s) ...\n", userClientSock, buffer);


        send_fd(workClientSock, userClientSock);


        //sleep (2);

        close(userClientSock);

    }


    close(workClientSock);

    /* NOT REACHED */

}



int send_fd(int fd, int sendfd)  

{   

    char c = 0;

    struct msghdr msg;  

    struct iovec iov[1];   

    union{

        struct cmsghdr cm;   

        char control[CMSG_SPACE(sizeof(int))];  

    }control_un;   

    struct cmsghdr *cmptr;   

    msg.msg_control = control_un.control;    

    msg.msg_controllen = sizeof(control_un.control);  

    cmptr = CMSG_FIRSTHDR(&msg);  

    cmptr->cmsg_len = CMSG_LEN(sizeof(int));

    cmptr->cmsg_level = SOL_SOCKET;    

    cmptr->cmsg_type = SCM_RIGHTS;

    *((int*)CMSG_DATA(cmptr)) = sendfd;

   

    msg.msg_name = NULL;  

    msg.msg_namelen = 0;   

   

    iov[0].iov_base = &c;  

    iov[0].iov_len = 1;  


    msg.msg_iov = iov;  

    msg.msg_iovlen = 1; 

    return sendmsg(fd, &msg, 0);  

}

UpperServer.c 


int main(int argc, char *argv[])

{

    int sock;                        /* Socket descriptor */

    int userClientSock;

    struct sockaddr_un masterListenAddr; /* Echo server address */


    char buffer[256];     /* Buffer for echo string */

    unsigned int n;      /* Length of string to echo */


    sock = socket(AF_UNIX, SOCK_STREAM, 0));


    bzero((char *) &masterListenAddr, sizeof(masterListenAddr));

    masterListenAddr.sun_family = AF_UNIX;

    strcpy(masterListenAddr.sun_path, "./socketfile");


    /* Establish the connection to the echo server */

    printf("connect to master ...\n");

    connect(sock, (struct sockaddr *) &masterListenAddr, sizeof(masterListenAddr));


    /* Send the string to the master server */

    strcpy(buffer, READY);

    n = 5;          /* Determine input length */

    printf("send 'READY' to listener ...\n");

    write(sock, buffer, n);


    printf("wait to receive FD ...\n");

    userClientSock = recv_fd(sock);

    close(sock);


    strcpy(buffer, READY);

    n = 5;          /* Determine input length */

    printf("send READY to client ...\n");

    write(userClientSock, buffer, n);


    while (1)

    {

        int i=0;

        n = read(userClientSock, buffer, RCVBUFSIZE - 1));


        printf("receive message from client: %s", buffer);      /* Print the echo buffer */

        for (i=0; i < n; i++)

            buffer[i] = toupper(buffer[i]);

        if (strncmp(buffer, "QUIT", 4) == 0 )

           break;


        write(userClientSock, buffer, n));

    }


    close(userClientSock);

    exit(0);

}



int recv_fd(int fd)  

{   

    int c = 0;

    struct msghdr msg;  

    struct iovec iov[1];  

    int n; 

    int newfd;   

    union{

    struct cmsghdr cm;   

    char control[CMSG_SPACE(sizeof(int))];  

    }control_un;   

    struct cmsghdr *cmptr;  

    msg.msg_control = control_un.control;   

    msg.msg_controllen = sizeof(control_un.control);  

       

    msg.msg_name = NULL;  

    msg.msg_namelen = 0;  

    iov[0].iov_base = &c;  

    iov[0].iov_len = 1;  

    msg.msg_iov = iov;  

    msg.msg_iovlen = 1;  

    if((n = recvmsg(fd, &msg, 0)) <= 0) 

    {   

        return n;  

    }   


    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");  

            exit(-1);  

        }   

        if(cmptr->cmsg_type != SCM_RIGHTS)  

        {   

            printf("control type != SCM_RIGHTS/n");  

            exit(-1);  

        } 

        int recvfd = *((int*)CMSG_DATA(cmptr)); 

        printf("recv FD %d\n", recvfd);

        return recvfd;

    }  

    else  

    {   

        if(cmptr == NULL) printf("null cmptr, fd not passed./n");  

        else printf("message len[%d] if incorrect./n", cmptr->cmsg_len);  

        return -1; // descriptor was not passed  

    }  


    return -1;

Client.c

/**

 * Usage: client $PORT $WORKER

 * For example: ./client 12345 UpperServer

 */

int main(int argc, char *argv[])

{

    int sock;

    struct sockaddr_in sock_addr;

    struct hostent *server;


    char buffer[256];

    int n;


    assert (argc == 3);


    sock = socket(AF_INET, SOCK_STREAM, 0);


    server = gethostbyname("localhost");


    bzero((char *) &sock_addr, sizeof(sock_addr));

    sock_addr.sin_family = AF_INET;

    bcopy((char *)server->h_addr, (char *)&sock_addr.sin_addr.s_addr, server->h_length);

    sock_addr.sin_port = htons(atoi(argv[1]));


    printf("connect to server %s...\n",argv[1]);

    connect(sock, (struct sockaddr *) &sock_addr,sizeof(sock_addr));


    strcpy(buffer, argv[2]);

    n = strlen(argv[2]);          /* Determine input length */

    write(sock, buffer, n);


    printf("waiting worker '%s' to startup ...\n", argv[2]);

    n = read(sock, buffer, 255));


    assert(strncmp(buffer, READY, strlen(READY)) != 0);


    /* Begin to receive the same string back from the server */

    while (1)

    {

        printf("Please enter the message(quit for quit): ");

        bzero(buffer,256);

        fgets(buffer,255,stdin);

        if (strncmp(buffer, "quit", strlen("quit")) == 0)

             break;

        n = write(sock, buffer, strlen(buffer));

        bzero(buffer,256);

        n = read(sock, buffer, 255);

        printf("Receive message from server: %s",buffer);

    }


    close(sock);

    return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值