Linux服务器套接字 - 错误的文件描述符
我在Linux下的服务器套接字有问题。出于某种原因,我不知道服务器套接字消失,并且在等待输入连接的select调用中出现Bad file descriptor
错误。当我在不同的线程中关闭不相关的套接字连接时,总是会出现此问题。这发生在2.6.36内核的嵌入式Linux上。Linux服务器套接字 - 错误的文件描述符
有谁知道为什么会发生这种情况?服务器插座是否可以简单地消失导致Bad file descriptor
是否正常?
编辑: 其他套接字代码实现了一个VNC服务器,并运行在一个完全不同的线程中。在其他代码中唯一特别的是使用setjmp/longjmp
,但这应该不成问题。
是创建服务器套接字的代码如下:
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;
}
我等待进来的连接使用下面的代码:
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;
}
编辑: 当问题的情况下发生我目前只是重新启动服务器,但我不明白为什么服务器套接字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;
}
在Linux中,一旦你创建了一个连接并且它被关闭了,那么你必须等待一段时间才能建立新的连接。 与Linux一样,套接字不释放端口号。只要你关闭了插座。
OR
你重用插座,再不济的文件描述符要来了。
它不是保留的IP地址(这将是严重的),但端口号 – 2012-07-31 08:09:47
@JensGustedt是其端口号。 – 2012-07-31 08:24:19
这只有在以下情况下才成立:(a)您创建的客户端连接不在此处发生,(b)您绑定到特定的出站端口号,不需要这样做,哪些也不会发生在这里,和(三)你是结束开始关闭。 -1完全和完全不相关。 – EJP 2014-07-25 23:34:27
您不区分代码中的两个错误情况,两者都可能失败select
或accept
。我的猜测是,你只是有一个时间,并选择返回0
。
- 打印
retval
和errno
在else
分支 - 调查
accept
返回值seperately - 确保
errno
重置为0
每个系统的前调用
插座(文件描述符)通常遭受与C
中的原始指针相同的管理问题。当你关闭套接字,不要忘记分配-1
,这样就保持了描述值的变量:
close(socket);
socket = -1;
正如你会做C
指针
free(buffer);
buffer = NULL;
如果你忘记这样做哟能后来关闭套接字两次,如果它是一个指针,你会两次访问内存两次。
另一个问题可能涉及到一个事实,即人们通常忘记:在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));
在这两种情况下my_data_1
和my_data_2
有一个有效的描述符(socket
)值。后来,一些代码,负责释放FooData
结构可能会盲目close()
这个描述符,这恰好是你服务器的侦听套接字(0
)。
谢谢!你的提示确实帮助我找到了一个邪恶的错误。 – jkow 2017-03-30 16:01:23
@jkow我很高兴这是有帮助的。别客气。 – GreenScape 2017-03-30 17:57:30
1-闭上你的插座:
close(sockfd);
2-清楚你的套接字文件从选择一套描述:
FD_CLR(sockfd,&master); //opposite of FD_SET
没有什么错,你发布的代码,误差必须在其他地方。例如,关闭它之后是否使用了套接字? – 2012-07-31 07:22:14
准确使用的线程在哪里? – 2012-07-31 07:32:10
上面的代码在一个线程中运行。另一个代码在另一个也运行线程的模块中。关闭连接将杀死服务器。我没有想过如果我没有关闭服务器套接字就会失效。 – trenki 2012-07-31 07:42:46