如何使用SENDMSG()通过套接字送2进程之间文件描述符? [英] How to use sendmsg() to send a file-descriptor via sockets between 2 processes?

查看:533
本文介绍了如何使用SENDMSG()通过套接字送2进程之间文件描述符?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在@cnicutar回答我这个<一个href=\"http://stackoverflow.com/questions/8457402/why-we-cannot-accept-a-socket-on-some-process-and-recv-data-from-its-child\">question,我试图从父进程发送一个文件描述符到其子。在此基础上<一href=\"http://publib.boulder.ibm.com/infocenter/iseries/v7r1m0/index.jsp?topic=/rzab6/xdescriptors.htm\">example,我写这篇code:

After @cnicutar answers me on this question, I tried to send a file-descriptor from the parent process to its child. Based on this example, I wrote this code:

int socket_fd ,accepted_socket_fd, on = 1;
int server_sd, worker_sd, pair_sd[2];
struct sockaddr_in client_address;
struct sockaddr_in server_address;

/* =======================================================================
 * Setup the network socket.
 * =======================================================================
 */

if((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
    perror("socket()");
    exit(EXIT_FAILURE);
}

if((setsockopt(socket_fd, SOL_SOCKET,  SO_REUSEADDR, (char *) &on, sizeof(on))) < 0)
{
    perror("setsockopt()");
    exit(EXIT_FAILURE);
}

server_address.sin_family = AF_INET;                 /* Internet address type */
server_address.sin_addr.s_addr = htonl(INADDR_ANY);  /* Set for any local IP */
server_address.sin_port = htons(port);               /* Set to the specified port */

if(bind(socket_fd, (struct sockaddr *) &server_address, sizeof(server_address)) < 0)
{
    perror("bind()");
    exit(EXIT_FAILURE);
}

if(listen(socket_fd, buffers) < 0)
{
    perror("listen()");
    exit(EXIT_FAILURE);
}

if(socketpair(AF_UNIX, SOCK_DGRAM, 0, pair_sd) < 0)
{
    socketpair("bind()");
    exit(EXIT_FAILURE);
}

server_sd = pair_sd[0];
worker_sd = pair_sd[1];



/* =======================================================================
 * Worker processes
 * =======================================================================
 */    

struct iovec   iov[1];
struct msghdr  child_msg;
char   msg_buffer[80];
int pass_sd, rc;


/* Here the parent process create a pool of worker processes (its children) */
for(i = 0; i < processes; i++)
{
    if(fork() == 0)
    {
        // ...

        /* Loop forever, serving the incoming request */
        for(;;)
        {

            memset(&child_msg,   0, sizeof(child_msg));
            memset(iov,    0, sizeof(iov));

            iov[0].iov_base = msg_buffer;
            iov[0].iov_len  = sizeof(msg_buffer);
            child_msg.msg_iov     = iov;
            child_msg.msg_iovlen  = 1;
            child_msg.msg_name    = (char *) &pass_sd;
            child_msg.msg_namelen = sizeof(pass_sd);

            printf("Waiting on recvmsg\n");
            rc = recvmsg(worker_sd, &child_msg, 0);
            if (rc < 0)
            {
               perror("recvmsg() failed");
               close(worker_sd);
               exit(-1);
            }
            else if (child_msg.msg_namelen <= 0)
            {
               printf("Descriptor was not received\n");
               close(worker_sd);
               exit(-1);
            }
            else
            {
               printf("Received descriptor = %d\n", pass_sd);
            }

            //.. Here the child process can handle the passed file descriptor
        }
    }

}



/* =======================================================================
 * The parent process
 * =======================================================================
 */

struct msghdr parent_msg;
size_t length;

/* Here the parent will accept the incoming requests and passed it to its children*/
for(;;)
{
    length = sizeof(client_address);
    if((accepted_socket_fd = accept(socket_fd, NULL, NULL)) < 0)
    {
        perror("accept()");
        exit(EXIT_FAILURE);
    }

    memset(&parent_msg, 0, sizeof(parent_msg));
    parent_msg.msg_name  = (char *) &accepted_socket_fd;
    parent_msg.msg_namelen = sizeof(accepted_socket_fd);

    if((sendmsg(server_sd, &parent_msg, 0)) < 0)
    {
        perror("sendmsg()");
        exit(EXIT_FAILURE);
    }

}

但不幸的是,我得到这个错误:

But unfortunately, I got this error:

sendmsg(): Invalid argument

我应该怎么做才能解决这个问题?和我使用正确指向msghdr 结构?因为在例子中,我上面提到的,它们使用 msg_accrights msg_accrightslen ,我得到了一些错误,当我使用它们,所以我不得不使用 msg_name msg_namelen 代替。

What should I do to fix this problem? and am I using the msghdr structure correctly? because in the example I mentioned above, they use msg_accrights and msg_accrightslen and I got some error when I use them so I had to use msg_name and msg_namelen instead.

推荐答案

这是非常难求的权利。我只是使用它会为你推荐的库。其中一个最简单的就是 libancillary 。它给你两个功能,一是通过UNIX域套接字发送文件描述符和一个接收一个。他们是太简单易用。

This is extremely hard to get right. I'd recommend just using a library that does it for you. One of the simplest is libancillary. It gives you two functions, one to send a file descriptor over a UNIX-domain socket and one to receive one. They are absurdly simple to use.

这篇关于如何使用SENDMSG()通过套接字送2进程之间文件描述符?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆