Unix域套接字传递文件描述符 - sendmsg:传输端点未连接

4

我一直在阅读博客和SO上的各种问题,试图理解如何使用Unix域套接字传递文件描述符。然而,我一直收到sendmsg错误提示-"Transport endpoint is not connected"。

我希望能得到帮助,了解我做错了什么。

服务器:

#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <unistd.h>
#include <QDebug>

char *socket_path = "/.socket";

ssize_t sock_fd_write(int sock, void *buf, ssize_t buflen, int fd)
{
    ssize_t     size;
    struct msghdr   msg;
    struct iovec    iov;
    union {
        struct cmsghdr  cmsghdr;
        char        control[CMSG_SPACE(sizeof (int))];
    } cmsgu;
    struct cmsghdr  *cmsg;

    iov.iov_base = buf;
    iov.iov_len = buflen;

    msg.msg_name = NULL;
    msg.msg_namelen = 0;
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    if (fd != -1) {
        msg.msg_control = cmsgu.control;
        msg.msg_controllen = sizeof(cmsgu.control);

        cmsg = CMSG_FIRSTHDR(&msg);
        cmsg->cmsg_len = CMSG_LEN(sizeof (int));
        cmsg->cmsg_level = SOL_SOCKET;
        cmsg->cmsg_type = SCM_RIGHTS;

        printf ("passing fd %d\n", fd);
        *((int *) CMSG_DATA(cmsg)) = fd;
    } else {
        msg.msg_control = NULL;
        msg.msg_controllen = 0;
        printf ("not passing fd\n");
    }

    printf ("sendmsg: %d\n", sock);

    size = sendmsg(sock, &msg, 0);

    if (size < 0)
        perror ("sendmsg");
    return size;
}

int main(int argc, char *argv[]) {
    struct sockaddr_un addr;
    char buf[100];
    int fd,cl,rc;

    if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        perror("socket error");
        exit(-1);
    }

    qDebug() << "Created Socket";

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);

    unlink(socket_path);

    int reuse = 1;
    int err = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
    if (0 == err) {
        err = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
        if ( err == -1 ) {
            perror("bind error");
            exit(-1);
        }
    }

    qDebug() << "Bound socket: " << fd;

    if (listen(fd, 5) == -1) {
        perror("listen error");
        exit(-1);
    }

    qDebug() << "Listening";

    while (1) {

        qDebug() << "About to accept";

        if ( (cl = accept(fd, NULL, NULL)) == -1) {
            perror("accept error");
            qDebug() << "Accept error";
            continue;
        }

        while ( (rc=read(cl,buf,sizeof(buf))) > 0) {

            printf("read %u bytes: %.*s\n", rc, rc, buf);

            qDebug() << "sock_fd_write: " << fd;

            ssize_t size;
            size = sock_fd_write(fd, (void*)"1", 1, 1);
            printf ("wrote %d\n", size);

        }
        if (rc == -1) {
            perror("read");
            exit(-1);
        }
        else if (rc == 0) {
            printf("EOF\n");
            close(cl);
        }
    }


    return 0;
}

客户端:

#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <QDebug>

char *socket_path = "/.socket";

ssize_t sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd) {

    ssize_t     size;

    if (fd) {
        struct msghdr   msg;
        struct iovec    iov;
        union {
            struct cmsghdr  cmsghdr;
            char        control[CMSG_SPACE(sizeof (int))];
        } cmsgu;
        struct cmsghdr  *cmsg;

        iov.iov_base = buf;
        iov.iov_len = bufsize;

        msg.msg_name = NULL;
        msg.msg_namelen = 0;
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;
        msg.msg_control = cmsgu.control;
        msg.msg_controllen = sizeof(cmsgu.control);
        size = recvmsg (sock, &msg, 0);
        if (size < 0) {
            perror ("recvmsg");
            exit(1);
        }
        cmsg = CMSG_FIRSTHDR(&msg);
        if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
            if (cmsg->cmsg_level != SOL_SOCKET) {
                fprintf (stderr, "invalid cmsg_level %d\n",
                         cmsg->cmsg_level);
                exit(1);
            }
            if (cmsg->cmsg_type != SCM_RIGHTS) {
                fprintf (stderr, "invalid cmsg_type %d\n",
                         cmsg->cmsg_type);
                exit(1);
            }

            *fd = *((int *) CMSG_DATA(cmsg));
            printf ("received fd %d\n", *fd);
        } else
            *fd = -1;
    } else {
        size = read (sock, buf, bufsize);
        if (size < 0) {
            perror("read");
            exit(1);
        }
    }
    return size;
}

int main(int argc, char *argv[]) {
    struct sockaddr_un addr;
    char buf[100];
    int fd,rc;

    if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        perror("socket error");
        exit(-1);
    }

    qDebug() << "Socket connected";

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);

    if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
        perror("connect error");
        exit(-1);
    }

    qDebug() << "Socket connected";

    ssize_t size;

    int fdRead;

    while( (rc=read(STDIN_FILENO, buf, sizeof(buf))) > 0) {

        qDebug() << "About to write";

        if (write(fd, buf, rc) != rc) {

            if (rc > 0) {

                qDebug() << "Partial write";

                size = sock_fd_read(fd, buf, sizeof(buf), &fdRead);
                if (size <= 0) {
                    break;
                }
                printf("read %d\n", size);
                if (fd != -1) {
                    write(fd, "hello, world\n", 13);
                    close(fd);
                }

            }
            else {

                perror("write error");
                exit(-1);

            }

        }
    }

    return 0;

}

4
sock_fd_write(fd, (void*)"1", 1, 1)"。看起来你正在向“listen”套接字(fd)写入,而不是“accept”套接字(cl)。 - kaylum
谢谢 - 请在下方回答,我会接受答案并点赞。 - PhilBot
1个回答

3
我需要使用接受套接字“cl”而不是监听套接字“fd”。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接