我正在C中编写一个TCP服务器,并发现一些不寻常的事情发生一旦听力FD得到“太多打开的文件”错误。 accept
调用不再阻止,并且始终返回-1。TCP服务器 - 从“太多打开的文件”恢复
我也尝试关闭收听fd并重新打开,重新绑定它,但似乎没有工作。
我的问题是,为什么accept
保持返回-1在这种情况下,我应该怎样做才能阻止它,使服务器能够接受新的连接任何老客户关闭后? (插座当然能够accept
时再正确一些连接关闭)
====== UPDATE:澄清======
只是因为有效客户的数量是出现该问题超过了开放文件系统的限制,所以我并没有close
示例代码中的任何公认fds,只是为了让它更快地复制。
我每次添加时间戳accept
返回输出,减缓connect
频率曾经在2秒钟,然后我发现其实在最新的成功accept
之后立即发生了“打开的文件太多”错误。所以我认为这是因为当maxium fds达到时,每个accept
的调用都会立即返回,返回值是-1。 (我认为accept
仍然会阻止,但在下一次传入connect
时返回-1。在这种情况下accept
的行为是我自己的理论,而不是来自手册页,如果它是错误的,请让我知道)。
因此,对于我的第二个问题,为了让它停止,我认为这是一个解决方案,在任何连接是close
d之前停止呼叫accept
。
也更新示例代码。谢谢你的帮助。
======示例代码======
以下是我如何测试它。首先将ulimit -n
设置为一个较低的值(如16)并运行由以下C源代码编译的服务器程序;然后使用Python脚本来创建几个连接
/* TCP server; bind :5555 */
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define BUFSIZE 1024
#define PORT 5555
void error(char const* msg)
{
perror(msg);
exit(1);
}
int listen_port(int port)
{
int parentfd; /* parent socket */
struct sockaddr_in serveraddr; /* server's addr */
int optval; /* flag value for setsockopt */
parentfd = socket(AF_INET, SOCK_STREAM, 0);
if (parentfd < 0) {
error("ERROR opening socket");
}
optval = 1;
setsockopt(parentfd, SOL_SOCKET, SO_REUSEADDR,
(const void *)&optval , sizeof(int));
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons((unsigned short)port);
if (bind(parentfd, (struct sockaddr *) &serveraddr, sizeof(serveraddr)) < 0) {
error("ERROR on binding");
}
if (listen(parentfd, 5) < 0) {
error("ERROR on listen");
}
printf("Listen :%d\n", port);
return parentfd;
}
int main(int argc, char **argv)
{
int parentfd; /* parent socket */
int childfd; /* child socket */
int clientlen; /* byte size of client's address */
struct sockaddr_in clientaddr; /* client addr */
int accept_count; /* times of accept called */
accept_count = 0;
parentfd = listen_port(PORT);
clientlen = sizeof(clientaddr);
while (1) {
childfd = accept(parentfd, (struct sockaddr *) &clientaddr, (socklen_t*) &clientlen);
printf("accept returns ; count=%d ; time=%u ; fd=%d\n", accept_count++, (unsigned) time(NULL), childfd);
if (childfd < 0) {
perror("error on accept");
/* the following 2 lines try to close the listening fd and re-open it */
// close(parentfd);
// parentfd = listen_port(PORT);
// the following line let the program exit at the first error
error("--- error on accept");
}
}
}
Python程序来创建连接
import time
import socket
def connect(host, port):
s = socket.socket()
s.connect((host, port))
return s
if __name__ == '__main__':
socks = []
try:
try:
for i in xrange(100):
socks.append(connect('127.0.0.1', 5555))
print ('connect count: ' + str(i))
time.sleep(2)
except IOError as e:
print ('error: ' + str(e))
print ('stop')
while True:
time.sleep(10)
except KeyboardInterrupt:
for s in socks:
s.close()
我注意到您的示例代码根本不涉及客户端。在评论中你说这是为了可读性......但这也可能隐藏了这个问题。例如,如果您调用'fork',则需要记住关闭** all **进程上的连接(只有当所有打开的句柄关闭时,连接才会被复制并关闭)。使用您的示例代码无法检查这些问题。现在,您只需要在客户端调用close,就像我之前的其他人所说的那样。 – Myst