套接字接受 – “打开文件太多”

我在一个学校项目上工作,我不得不编写一个multithreading服务器,现在我通过运行一些testing来比较它到Apache。 我正在使用autobench来帮助解决这个问题,但是在我运行一些testing之后,或者如果我给它一个太高的速度(大约600+)来build立连接,我会得到一个“太多打开文件”的错误。

在处理完请求之后,我总是在socket上做一个close() 。 我试图使用shutdown()函数,但似乎没有任何帮助。 有什么办法呢?

Linux有多个地方可以限制您允许打开的文件描述符的数量。

您可以检查以下内容:

 cat /proc/sys/fs/file-max 

这将给你的文件描述符的系统范围的限制。

在shell级别上,这会告诉你你的个人限制:

 ulimit -n 

这可以在/etc/security/limits.conf中改变 – 这是nofile参数。

但是,如果你正确地closures你的套接字,除非你打开大量的同步连接,否则你不应该接收这个套接字。 这听起来像是有什么东西阻止你的sockets被适当closures。 我会validation他们正在处理正确。

我有类似的问题。 快速解决scheme是:

 ulimit -n 4096 

解释如下 – 每个服务器连接都是一个文件描述符。 在CentOS中,Redhat和Fedora,可能是其他的,文件用户限制是1024 – 不知道为什么。 当你input:ulimit -n时可以很容易的看到

请注意,这与系统最大文件(/ proc / sys / fs / file-max)没有多大关系。

在我的情况下,这是Redis的问题,所以我做了:

 ulimit -n 4096 redis-server -c xxxx 

在你的情况而不是redis,你需要启动你的服务器。

TCP有一个名为“TIME_WAIT”的function,确保连接完全closures。 它要求连接的一端在套接字closures后保持监听一段时间。

在高性能服务器中,重要的是进入TIME_WAIT的客户端,而不是服务器。 客户端可以承担打开端口,而繁忙的服务器可以快速耗尽端口或打开FD太多。

要做到这一点,服务器不应该首先closures连接 – 它应该始终等待客户端closures它。

我也有这个问题。 你有一个文件句柄泄漏。 您可以通过打印出所有打开文件句柄(在POSIX系统上)的列表来进行debugging:

 void showFDInfo() { s32 numHandles = getdtablesize(); for ( s32 i = 0; i < numHandles; i++ ) { s32 fd_flags = fcntl( i, F_GETFD ); if ( fd_flags == -1 ) continue; showFDInfo( i ); } } void showFDInfo( s32 fd ) { char buf[256]; s32 fd_flags = fcntl( fd, F_GETFD ); if ( fd_flags == -1 ) return; s32 fl_flags = fcntl( fd, F_GETFL ); if ( fl_flags == -1 ) return; char path[256]; sprintf( path, "/proc/self/fd/%d", fd ); memset( &buf[0], 0, 256 ); ssize_t s = readlink( path, &buf[0], 256 ); if ( s == -1 ) { cerr << " (" << path << "): " << "not available"; return; } cerr << fd << " (" << buf << "): "; if ( fd_flags & FD_CLOEXEC ) cerr << "cloexec "; // file status if ( fl_flags & O_APPEND ) cerr << "append "; if ( fl_flags & O_NONBLOCK ) cerr << "nonblock "; // acc mode if ( fl_flags & O_RDONLY ) cerr << "read-only "; if ( fl_flags & O_RDWR ) cerr << "read-write "; if ( fl_flags & O_WRONLY ) cerr << "write-only "; if ( fl_flags & O_DSYNC ) cerr << "dsync "; if ( fl_flags & O_RSYNC ) cerr << "rsync "; if ( fl_flags & O_SYNC ) cerr << "sync "; struct flock fl; fl.l_type = F_WRLCK; fl.l_whence = 0; fl.l_start = 0; fl.l_len = 0; fcntl( fd, F_GETLK, &fl ); if ( fl.l_type != F_UNLCK ) { if ( fl.l_type == F_WRLCK ) cerr << "write-locked"; else cerr << "read-locked"; cerr << "(pid:" << fl.l_pid << ") "; } } 

通过倾销所有打开的文件,您将快速找出您的文件处理泄漏的位置。

如果你的服务器产生subprocess。 例如,如果这是一个“fork”风格的服务器,或者你正在产生其他进程(例如通过cgi),你必须确保使用“cloexec”创build文件句柄 – 无论是真实文件还是套接字。

如果没有cloexec,每次fork或产卵时,所有打开的文件句柄都被克隆到subprocess中。

closuresnetworking套接字也很容易,比如在远程方断开连接时丢弃它们。 这会像疯了似的泄漏处理。

使用lsof -u `whoami` | wc -l lsof -u `whoami` | wc -lfind用户有多less个打开的文件

在封闭的套接字真正被释放之前,可能需要一些时间

lsof列出打开的文件

cat /proc/sys/fs/file-max来查看是否有系统限制

这意味着同时打开文件的最大数量。

解决了:

在文件/etc/security/limits.conf的结尾处,您需要添加以下行:

 * soft nofile 16384 * hard nofile 16384 

在当前控制台从根(sudo不起作用)来做:

 ulimit -n 16384 

尽pipe这是可选的,但如果可以重新启动服务器。

/etc/nginx/nginx.conf文件中注册新的值worker_connections等于16384除以值worker_processes

如果没有做了ulimit -n 16384 ,需要重启,那么问题就会消失。

PS:

如果在日志中可见修复后error accept() failed (24: Too many open files)

在nginxconfiguration中,propevia(例如):

 worker_processes 2; worker_rlimit_nofile 16384; events { worker_connections 8192; } 

当你的程序有更多的开放描述符比打开的文件ulimit(ulimit -a会列出这个),内核将拒绝打开更多的文件描述符。 确保没有任何文件描述符泄漏 – 例如,运行一段时间,然后停止并查看是否有任何额外的fds在闲置时仍然打开 – 如果仍存在问题,请更改您的nofile ulimit用户在/etc/security/limits.conf中

我有同样的问题,我不打扰检查close()调用的返回值。 当我开始检查返回值时,这个问题神秘地消失了。

我只能假设编译器的优化故障(在我的情况下是gcc),假设close()调用没有副作用,如果不使用它们的返回值,可以省略。

只是关于CentOS的另一个信息。 在这种情况下,使用“systemctl”启动进程。 您必须修改系统文件==> /usr/lib/systemd/system/processName.service。在文件中添加以下行:

 LimitNOFILE=50000 

只需重新加载你的系统conf:

 systemctl daemon-reload