来自TCP套接字的recv上的错误文件描述符

时间:2015-11-10 18:21:22

标签: c linux sockets tcp parallel-processing

我遇到了麻烦,无法解决问题,所以我希望您能够帮助我。

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

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 
}

接下来,接收器获取新套接字的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_block lc_send_non_block 只是正常的 recv 发送,并为EAGAIN和EWOULDBLOCK提供了额外的错误处理功能(使用select()来避免问题)。

由于某种原因,在这一行,recv()因errno EBADF而失败。

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

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

1 个答案:

答案 0 :(得分:0)

查看sendmsg()Unix domain sockets API,尤其是SCM_RIGHTS message type。基本上,您使用SCM_RIGHTS消息类型和文件描述符数组构建消息。在封面下,接收方有效dup()文件描述符,可以访问这些文件。

这是特定于Linux的。