遇到一个因socket未关闭引发的文件句柄用完问题
来源:互联网 发布:雅克萨之战 知乎 编辑:程序博客网 时间:2024/05/29 09:34
“爱提踢斯”项目最近遇到一个问题,当FTP服务器磁盘没有空间时,设备会不断复位——这是测试人员反馈的。我们拿到log后,看到一个通信所用的文件打开失败。不断打印Too many open file,然后超时设备复位。同时我们看到数据库文件打开失败,无法写入数据。一个现象,看到好几处问题。还是从最初的表现来入手。虽然把bug指派给别人,但从时间、进度上考虑,周末还是去加班。而最后,解决了问题。根据老夫目测,是FTP的socket未关闭引起的。
linux系统的文件句柄(我很想说“文件描述符”,但“句柄”似乎更多人使用)是有限制的。查看系统支持句柄最大值用如下命令:
# ulimit -n
1024
可见,默认是1024。
下面用代码来说明一下问题。代码如下:
/**系统一次允许最大的文件句柄为1024。open foobar file for: 340open bar file for: 340open foo file for: 341open foobar file failed: : Too many open filesopen BAR file failed: : Too many open files# ulimit -a...open files (-n) 1024...*/#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>int foo(void){ static int cnt = 1; int ret = 0; int fd =-1;char buf[5] = {0}; char read_buf[5] = {0}; fd = open("/tmp/FOO.txt",O_RDWR|O_CREAT,0666); if(fd < 0) { perror("open FOO file failed: "); return -1; } printf("open foo file for: %d\n", cnt++);return 0;}int bar(void){ static int cnt = 1; int ret = 0; int fd =-1;char buf[5] = {0}; char read_buf[5] = {0}; fd = open("/tmp/BAR.txt",O_RDWR|O_CREAT,0666); if(fd < 0) { perror("open BAR file failed: "); return -1; } printf("open bar file for: %d\n", cnt++);return 0;}int foobar(void){ static int cnt = 1; int ret = 0; int fd =-1;char buf[5] = {0}; char read_buf[5] = {0}; fd = open("/tmp/foobar.txt",O_RDWR|O_CREAT,0666); if(fd < 0) { perror("open foobar file failed: "); return -1; } printf("open foobar file for: %d\n", cnt++);return 0;}int main(void){ int ret = 0; while (1) { foo();usleep(1); foobar();usleep(1); ret = bar(); // if (ret < 0) break; // 不让其退出 usleep(100); } return 0;}
要查看这个进程占用文件句柄数,先获取该进程PID:
# ps -ef | grep a.out
root 17835 7615 17 23:01 pts/1 00:00:00 ./a.out
我们查看该进程文件句柄最大值:
# cat /proc/17835/limits | grep "files"
Max open files 1024 4096 files
和系统默认值一样。查看已占用值:
# ll /proc/17835/fd | wc -l
1027
我们看到,已经占用上千个句柄,一直未释放。当达到系统最大值时,就会报Too many open files的错误。
匆匆已然四载,不曾想到,当年刚入职搞FTP的我,竟然会埋下地雷,让今天的我不幸踩中。在没有离职情况下,只好义无反顾地去解决bug。——而这个bug,正是因为未关闭socket造成的。
FTP客户端的实现,是需要打开2个socket的,一个是命令通道,一个是数据通道。在服务器没有磁盘空间情况下,write数据是返回错误的,使用FTP模块者认为是无法登陆,下次会再次尝试登陆——在这种情况下,登陆是正常的,只是无法写数据。但每次登陆,都会创建命令通道的socket,这导致了socket的泄漏,不会关闭,因为使用者并没有调用logout函数退出登陆。另一个问题是最主要的,每次写数据时,要创建数据通道的socket,但在出错时,并没有关闭数据通道的socket,而是直接返回。这再次导致了socket泄漏。找到了原因,解决起来就好办了。
自从知道可以查看某个进程占用的文件句柄,我去看看以前的设备,发现有个别文件占用句柄较多——也就几十个。目测是只打开但未关闭。出于热心,我把情况在部门群里说了,至于后续的事,因为那些不是我的职责范围,不敢越趄代庖。
2015.8.1 李迟
- 遇到一个因socket未关闭引发的文件句柄用完问题
- Perl 循环内没关闭文件句柄引发的问题
- 遇到一个日志文件变化带来的文件句柄问题
- 一个office未激活引发的问题
- 遇到一个在脚本中读取文件内容占用文件句柄的小问题
- AsyncTask引发的一个问题:doInBackground()未及时执行
- 因C#一段代码,引发的问题
- 一个.tar.gz文件引发的问题
- mv遇到空格和小括号文件引发的问题
- 【JAVA】Socket文件上传遇到的问题!~
- Socket引发的死锁问题。
- 一个未初始化引发的灾难
- 一个因全局变量引起的DLL崩溃引发的血案
- JNI遇到的问题:未找到.h 文件
- 遇到一个Linux文件系统因bios时间错误变成只读的问题
- Socket遇到的问题
- 遇到一个数据库链接未释放问题
- Python中的一个文件句柄问题
- DeepID2——强大的人脸分类算法
- linux基础知识二
- 力克·胡哲经典励志名言
- Windows 8.1系统上网经常掉线解决方法
- 画圆方法小结
- 遇到一个因socket未关闭引发的文件句柄用完问题
- 连动菜单---【菜鸟自娱】
- 实习之网页设计总结
- BP神经网络 语音信号分类
- MSP430F5529的IO口管脚的中断学习笔记
- iOS 记住密码\自动登录
- java静态代码块
- 计算机物理学-刚体动力学(2)
- 5-从尾到头打印链表