我遇到了麻烦,无法解决问题,所以我希望您能够帮助我。
有一个客户端 - 服务器应用程序,比如文本聊天 服务器接受客户端的连接,为客户端创建新的套接字,并向其子进程发送套接字描述符,将所接收的消息广播到所有连接的客户端。
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);
我错过了什么以及为什么文件描述符被破坏了?
答案 0 :(得分:0)
查看sendmsg()的Unix domain sockets API,尤其是SCM_RIGHTS message type。基本上,您使用SCM_RIGHTS消息类型和文件描述符数组构建消息。在封面下,接收方有效dup()
文件描述符,可以访问这些文件。
这是特定于Linux的。