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

Erlang新增进程层后监听套接字accept连接立即返回closed错误

问题原因

Erlang的TCP套接字(包括监听套接字)默认归创建它的进程所有,一旦所属进程退出,系统会自动关闭该套接字,这是问题的核心诱因:

  • 修改后的代码中,start_listening/2 函数是在独立spawn的进程中执行的,它完成「创建监听套接字、启动accept服务进程、获取端口号」这一系列逻辑后,函数执行结束,该进程就直接正常退出了
  • 进程退出后,它创建的监听套接字被系统自动关闭,此时已经启动的accept进程调用gen_tcp:accept(LS)时,操作的是已经关闭的监听套接字,就会立即返回{error,closed}错误
解决方案

有三个常用的修复方案,按需选择即可:

方案1:让监听套接字的创建进程保持存活

修改start_listening/2函数,在逻辑执行完成后让进程阻塞挂住不退出,即可维持监听套接字存活,修改示例:

start_listening(Num,LPort) ->
  case gen_tcp:listen(LPort,[{active, false},{packet,0}]) of
    {ok, ListenSock} ->
      start_servers(Num,ListenSock),
      {ok, Port} = inet:port(ListenSock),
      %% 新增阻塞逻辑,进程永远挂住不退出,也可以自定义停止信号实现服务关停
      receive
        stop -> ok
      end;
    {error,Reason} ->
      {error,Reason}
  end.

方案2:创建监听套接字的进程自身承担accept逻辑

把创建监听套接字的进程也作为accept工作进程使用,自然不会提前退出,修改示例:

start_listening(Num,LPort) ->
  case gen_tcp:listen(LPort,[{active, false},{packet,0}]) of
    {ok, ListenSock} ->
      %% 少启动1个工作进程,当前进程自己承担accept任务
      start_servers(Num-1,ListenSock),
      {ok, Port} = inet:port(ListenSock),
      %% 直接进入accept循环
      server(ListenSock);
    {error,Reason} ->
      {error,Reason}
  end.

方案3:转移监听套接字的控制进程

在创建监听套接字后,将它的控制进程转移给任意一个不会退出的进程(比如第一个启动的accept工作进程),转移后原创建进程退出就不会关闭套接字了,转移调用语法:

%% 把ListenSock的控制进程从当前进程改为目标进程TargetPid
inet:controlling_process(ListenSock, TargetPid)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 10:36:04