Linux 服务器套接字 - 错误的文件描述符
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11735014/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Linux server socket - Bad file descriptor
提问by trenki
I have a problem with a server socket under Linux. For some reason unknown to me the server socket vanishes and I get a Bad file descriptor
error in the select call that waits for an incomming connection. This problem always occurs when I close an unrelated socket connection in a different thread. This happens on an embedded Linux with 2.6.36 Kernel.
我在 Linux 下的服务器套接字有问题。由于某种我不知道的原因,服务器套接字消失了,我Bad file descriptor
在等待传入连接的选择调用中出现错误。当我在不同的线程中关闭一个不相关的套接字连接时,总是会出现这个问题。这发生在具有 2.6.36 内核的嵌入式 Linux 上。
Does anyone know why this would happen? Is it normal that a server socket can simply vanish resulting in Bad file descriptor
?
有谁知道为什么会发生这种情况?服务器套接字可以简单地消失导致Bad file descriptor
?
edit:The other socket code implements a VNC Server and runs in a completely different thread. The only thing special in that other code is the use of setjmp/longjmp
but that should not be a problem.
编辑:另一个套接字代码实现了一个 VNC 服务器并在一个完全不同的线程中运行。其他代码中唯一特别的是使用setjmp/longjmp
但这应该不是问题。
The code that create the server socket is the following:
创建服务器套接字的代码如下:
int server_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in saddr;
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
saddr.sin_port = htons(1234);
const int optionval = 1;
setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &optionval, sizeof(optionval));
if (bind(server_socket, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
perror("bind");
return 0;
}
if (listen(server_socket, 1) < 0) {
perror("listen");
return 0;
}
I wait for an incomming connection using the code below:
我使用以下代码等待传入连接:
static int WaitForConnection(int server_socket, struct timeval *timeout)
{
fd_set read_fds;
FD_ZERO(&read_fds);
int max_sd = server_socket;
FD_SET(server_socket, &read_fds);
// This select will result in 'EBADFD' in the error case.
// Even though the server socket was not closed with 'close'.
int res = select(max_sd + 1, &read_fds, NULL, NULL, timeout);
if (res > 0) {
struct sockaddr_in caddr;
socklen_t clen = sizeof(caddr);
return accept(server_socket, (struct sockaddr *) &caddr, &clen);
}
return -1;
}
edit:When the problem case happens i currently simply restart the server but I don't understand why the server socket id should suddenly become an invalid file descriptor:
编辑:当问题发生时,我目前只是重新启动服务器,但我不明白为什么服务器套接字 id 突然变成无效的文件描述符:
int error = 0;
socklen_t len = sizeof (error);
int retval = getsockopt (server_socket, SOL_SOCKET, SO_ERROR, &error, &len );
if (retval < 0) {
close(server_socket);
goto server_start;
}
回答by Rahul Bhansali
In Linux once you create a connection and it get closed then you have to wait for some time before making new connection. As in Linux, socket doesn't release the port no. as soon as you close the socket.
在 Linux 中,一旦你创建了一个连接并且它被关闭,那么你必须等待一段时间才能建立新的连接。在 Linux 中,socket 不会释放端口号。一旦关闭套接字。
OR
或者
You reuse the socket, then bad file descriptor want come.
你重用套接字,然后坏文件描述符要来了。
回答by Jens Gustedt
You don't distinguish the two error cases in your code, both can fail select
or accept
. My guess is that you just have a time out and that select returns 0
.
您不区分代码中的两种错误情况,两者都可能失败select
或accept
. 我的猜测是你只是有时间,然后选择返回0
。
- print
retval
anderrno
in anelse
branch - investigate the return value of
accept
seperately - ensure that
errno
is reset to0
before each of the system calls
- 打印
retval
并errno
在else
分支中 - 调查的返回值
accept
seperately - 确保在每个系统调用之前
errno
重置为0
回答by GreenScape
Sockets (file descriptors) usually suffer from the same management issues as raw pointers in C
. Whenever you close a socket, do not forget to assign -1
to the variable that keeps the descriptor value:
套接字(文件描述符)通常会遇到与C
. 每当您关闭套接字时,不要忘记分配-1
给保持描述符值的变量:
close(socket);
socket = -1;
As you would do to C
pointer
就像你对C
指针所做的那样
free(buffer);
buffer = NULL;
If you forget to do this yo can later close socket twice, as you would free()
memory twice if it was a pointer.
如果你忘记这样做,你可以稍后关闭套接字两次,因为free()
如果它是一个指针,你会记忆两次。
The other issue might be related to the fact that people usually forget: file descriptors in UNIX environment start from 0
. If somewhere in the code you have
另一个问题可能与人们通常忘记的事实有关:UNIX 环境中的文件描述符从0
. 如果代码中的某个地方你有
struct FooData {
int foo;
int socket;
...
}
// Either
FooData my_data_1 = {0};
// Or
FooData my_data_2;
memset(&my_data_2, 0, sizeof(my_data_2));
In both cases my_data_1
and my_data_2
have a valid descriptor (socket
) value. And later, some piece of code, responsible for freeing FooData
structure may blindly close()
this descriptor, that happens to be you server's listening socket (0
).
在这两种情况下my_data_1
,my_data_2
都有一个有效的描述符 ( socket
) 值。后来,一些负责释放FooData
结构的代码可能会盲目地使用close()
这个描述符,这恰好是您服务器的侦听套接字(0
)。
回答by Iman Mirzadeh
1- close your socket:
1-关闭你的插座:
close(sockfd);
2- clear your socket file descriptor from select set:
2- 从选择集中清除您的套接字文件描述符:
FD_CLR(sockfd,&master); //opposite of FD_SET