从 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_block和lc_send_non_block只是正常的recv 和 send 以及针对 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 的。
我遇到了麻烦,无法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_block和lc_send_non_block只是正常的recv 和 send 以及针对 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 的。