从 TCP 套接字接收到的错误文件描述符

Bad File Descriptor on recv from TCP socket

我遇到了麻烦,无法google解决,所以我希望你能帮助我。

有一个客户端-服务器应用程序,类似于文本聊天。
服务器接受客户端的连接,为客户端创建新的套接字并将套接字描述符发送到它的子进程,子进程将接收到的消息广播给所有连接的客户端。

server.c(删去错误处理和测试)

/* structure with fd, sockaddr_in and sockaddrlen */
Socket_in listener;
memset(&listener, 0, sizeof(Socket_in));

listener.saddr.sin_addr.s_addr = htonl(INADDR_ANY);
listener.saddr.sin_family = AF_INET;
listener.saddr.sin_port = htons(conf.port);
listener.slen = sizeof(listener.saddr);

listener.fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)

/* Bind socket to port */
bind(listener.fd, (struct sockaddr*)&listener.saddr, listener.slen);

/* socktrans is UNIX-socket for IPC between main process and child */
int pid = fork_receiver(socktrans);

while(1){
    struct sockaddr_in newcliaddr;
    uint nclilen = sizeof(newcliaddr);
    int newsockfd = accept(listener.fd, (struct sockaddr*)&newcliaddr, &nclilen);

    flags = fcntl(newsockfd, F_GETFL, 0);
    fcntl(newsockfd, F_SETFL, flags | O_NONBLOCK)

   /* Sending connected client socket fd to child process */
    sendto(socktrans.fd, &newsockfd, sizeof(newsockfd), 0, (struct 
}

接下来,receiver获取新socket的fd并将其保存到一个数组中。 接收者的代码如下所示:

int pid = fork();
if(pid < 0)        // fork() failed
    return -1;
if(pid > 0)         // it's parent process -> return child's pid
    return pid;

/* Now we are in child process */
struct fds_s fds;
fds.fds = NULL;
fds.count = 0;

int n, i;
message msg;
int     newclientfd;

while(1){
    memset(&msg, 0, sizeof(msg));
    n = lc_recv_non_block(socktrans.fd, &newclientfd, sizeof(newclientfd), 0);
    if(n > 0){
        add_client(&fds, newclientfd);

    for(i = 0; i < fds.count; i++){
        int fd = fds.fds[i];
        n = lc_recv_non_block(fd, &msg, sizeof(msg), 0);
        if(n > 0){
            broadcast(&bay, &msg, sizeof(msg));
        }
    }
}

exit(0);

这里的函数lc_recv_non_blocklc_send_non_block只是正常的recvsend 以及针对 EAGAIN 和 EWOULDBLOCK 的额外错误处理(使用 select() 来避免问题)。

出于某种原因,在这一行 recv() 失败并返回错误号 EBADF。

n = lc_recv_non_block(fd, &msg, sizeof(msg), 0);

我错过了什么以及为什么文件描述符损坏了?

看看sendmsg() API for Unix domain sockets, especially the SCM_RIGHTS message type。基本上,您使用 SCM_RIGHTS 消息类型和文件描述符数组构建消息。在接收方的幕后,有效地 dup()s 允许访问这些文件的文件描述符。

这是非常 Linux 的。