设置ulimit -n为无限制仍遇C共享库"Too Many Files Open"错误
问题:拦截connect系统调用的共享库出现"Too Many Files Open"错误
我正在开发一个C程序,创建共享库拦截connect系统调用,将连接路由至代理服务器。代码可正常运行,但运行一段时间后会出现"Too Many Files Open"错误,尽管已将ulimit -n设置为无限制。
相关代码
toralize.c
#include "toralize.h" Req *request(struct sockaddr_in *sock2) { Req *req; req = malloc(reqsize); if (req == NULL) { perror("malloc"); return NULL; // Handle the error appropriately in the calling function } req->vn = 4; req->cd = 1; req->dstip = sock2->sin_addr.s_addr; req->dstport = sock2->sin_port; strncpy(req->userid, USERNAME, 8); return req; } int connect(int s2, const struct sockaddr *sock2, socklen_t addrlen) { int s; Req *req; Res *res; struct sockaddr_in sock; char buf[ressize]; int success; int (*p)(int, const struct sockaddr*, socklen_t); p = dlsym(RTLD_NEXT, "connect"); if (p == NULL) { perror("dlsym"); return -1; } s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { perror("socket"); return -1; } sock.sin_family = AF_INET; sock.sin_port = htons(PROXYPORT); sock.sin_addr.s_addr = inet_addr(PROXY); printf("Connecting to %s:%d\n", inet_ntoa(sock.sin_addr), ntohs(sock.sin_port)); if (p(s, (struct sockaddr *)&sock, sizeof(sock)) < 0) { perror("connect"); close(s); return -1; } printf("Connected to proxy.\n"); req = request((struct sockaddr_in *)sock2); if (req == NULL) { close(s); return -1; } if (write(s, req, reqsize) < 0) { perror("write"); free(req); close(s); return -1; } memset(buf, 0, ressize); if (read(s, buf, ressize) < 1) { perror("read"); free(req); close(s); return -1; } res = (Res *)buf; success = (res->cd == 90); if (!success) { fprintf(stderr, "Unable to traverse" "the proxy, error code: %d\n", res->cd); close(s); free(req); return -1; } printf("Connected through the proxy.\n"); close(s2); if (dup2(s, s2) < 0) { perror("dup2"); free(req); close(s); return -1; } close(s); free(req); return 0; }
toralize.h
/* toralize.h */ #include<stdio.h> #include<string.h> #include<stdlib.h> #include<unistd.h> #include<sys/socket.h> #include<arpa/inet.h> #include<netinet/in.h> #include<dlfcn.h> #define PROXY "127.0.0.1" #define PROXYPORT 9050 #define reqsize sizeof(struct proxy_request) #define ressize sizeof(struct proxy_response) #define USERNAME "toraliz" typedef unsigned char int8; typedef unsigned short int int16; typedef unsigned int int32; struct proxy_request { int8 vn; int8 cd; int16 dstport; int32 dstip; unsigned char userid[8]; }; typedef struct proxy_request Req; struct proxy_response { int8 vn; int8 cd; int16 _; int32 __; }; typedef struct proxy_response Res; Req *request(struct sockaddr_in*); int connect(int, const struct sockaddr*, socklen_t);
编译命令
gcc toralize.c -o toralize.so -fPIC -shared -ldl -D_GNU_SOURCE
已尝试操作
- 确认
ulimit -n已设置为无限制; - 检查代码中可能未正确关闭文件描述符的位置。
疑问
- 此场景下导致"Too Many Files Open"错误的原因可能是什么?
- 如何更有效地修复或调试该问题?
问题分析与解决方案
可能的泄漏原因
从代码逻辑看,大部分错误路径都已正确关闭socket描述符s,但仍存在以下潜在问题:
- 上层应用未关闭原socket:
dup2成功后,原s2被替换为代理连接的描述符,若上层应用长期持有该描述符不关闭,会导致累积泄漏; close调用失败未被检测:部分close操作可能因描述符无效等原因失败,但代码未检查返回值,无法发现此类异常;- 线程安全隐患:多线程并发调用时,若未正确处理全局资源(如后续优化的
dlsym缓存),可能导致描述符管理混乱; - 冗余的
close(s2):手动close(s2)后调用dup2,若s2已失效,可能触发不必要的错误,干扰正常流程。
调试与修复步骤
添加
close错误检查:给所有close调用添加返回值校验,确保描述符被正确关闭:if (close(s) < 0) { perror("close proxy socket"); }添加文件描述符计数监控:用原子变量统计打开/关闭的描述符数量,实时监控泄漏情况:
#include <stdatomic.h> atomic_int fd_counter = 0; // 创建socket成功后 atomic_fetch_add(&fd_counter, 1); // 关闭socket前 atomic_fetch_sub(&fd_counter, 1); // 在connect函数中打印计数 printf("Current FD count: %d\n", atomic_load(&fd_counter));用
lsof定位泄漏:运行程序时,通过lsof -p <进程PID>实时查看打开的文件描述符,确认是否有大量未关闭的socket描述符。优化
dlsym调用:将系统connect函数指针缓存为静态变量,避免重复调用dlsym:static int (*p)(int, const struct sockaddr*, socklen_t) = NULL; if (p == NULL) { p = dlsym(RTLD_NEXT, "connect"); if (p == NULL) { perror("dlsym"); return -1; } }替换过时的
inet_addr:用inet_pton替代inet_addr,增强IP地址解析的错误处理:if (inet_pton(AF_INET, PROXY, &sock.sin_addr) != 1) { perror("inet_pton"); close(s); return -1; }移除冗余的
close(s2):让dup2自动处理原描述符的关闭,避免重复操作引发的异常:// 移除 close(s2); if (dup2(s, s2) < 0) { perror("dup2"); free(req); close(s); return -1; }
内容的提问来源于stack exchange,提问作者Faraz
相关产品推荐
相关产品推荐

