You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux无法创建足够UDP套接字但实际套接字占用量较低问题求助

问题成因

核心异常对应三个底层原因:

  1. errno显示为0的问题
    你现有代码执行顺序为:调用setsockopt()→执行printf()→错误分支读取errno。而printf等标准库函数执行成功时会重置errno为0,你拿到的errno已经被printf覆盖,并非setsockopt出错时的真实错误码。
  2. 仅能创建2个UDP套接字、第三次就拿到fd=1023的问题
    你认知中的「单个进程套接字上限1023」实际是进程默认的文件描述符上限:Linux下进程默认允许打开的最大文件描述符数量为1024,fd编号范围是0~1023。该限制是单进程维度的,你用ss -s看到的是全局系统的套接字占用,和单个进程的fd占用没有关联。
    当前进程在创建这几个UDP套接字之前,已经打开了大量其他文件描述符(可能是常规文件、管道、其他套接字、目录句柄等),占满了0~1022的fd编号,所以新创建的socket只能拿到1023这个最后可用的fd。
  3. setsockopt本身失败的潜在原因
    排除fd已满的问题外,还有两个常见触发点:
  • 你定义的yes变量类型是u_int,而SO_REUSEADDR要求的入参是int类型,部分架构下两种类型长度不一致会导致参数校验失败
  • 你代码中的assert写法错误:C语言assert仅接收一个表达式参数,你写的assert(sock != -1, strerror(errno))是逗号表达式,第二个参数会被直接忽略,即便socket创建失败也无法正确触发断言,遗漏了前置错误。
排查解决步骤
  • 首先修复错误码获取逻辑:调用setsockopt后先备份errno,避免被标准库函数覆盖:
int result = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
int saved_errno = errno; // 先备份errno
printf("sock=%i result=%i errno=%i\n", sock, result, saved_errno);
if(result != 0)
{
    FATAL(strerror(saved_errno));
}
  • 检查进程当前的文件描述符占用:进程运行时查看/proc/<pid>/fd目录下的文件数量,确认是否已经占满了默认的1024个fd上限,修复未正常关闭资源的逻辑。
  • 调整进程文件描述符上限:如果确实需要大量fd,可以通过ulimit -n 4096临时调高当前shell启动进程的fd上限,永久修改可以编辑/etc/security/limits.conf配置。
  • 修正SO_REUSEADDR入参类型:把yes变量的类型改为标准的int,避免类型不匹配导致的参数错误。
  • 修复assert写法:改为assert(sock != -1 && strerror(errno)),或者直接用if分支处理socket创建失败的场景。

内容的提问来源于stack exchange,提问作者user997112

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 16:27:03