Erlang在socket中接受连接只有在有多层进程时才会失败
Erlang accepting connection in socket fails only when there are multiple layers of processes
我运行遇到了一个st运行ge问题。我正在测试 docs 中的代码,该代码创建多个进程以接受来自侦听套接字的传入连接:
-module(servertest).
%% API
-export([start/2, server/1]).
start(Num,LPort) ->
case gen_tcp:listen(LPort,[{active, false},{packet,0}]) of
{ok, ListenSock} ->
start_servers(Num,ListenSock),
{ok, Port} = inet:port(ListenSock),
Port;
{error,Reason} ->
{error,Reason}
end.
start_servers(0,_) ->
ok;
start_servers(Num,LS) ->
spawn(?MODULE,server,[LS]),
start_servers(Num-1,LS).
server(LS) ->
io:format("server started~n", []),
case gen_tcp:accept(LS) of
{ok,S} ->
loop(S),
server(LS);
Other ->
io:format("accept returned ~w - goodbye!~n",[Other]),
ok
end.
loop(S) ->
inet:setopts(S,[{active,once}]),
receive
{tcp,S,Data} ->
Answer = Data, % Not implemented in this example
gen_tcp:send(S,Answer),
loop(S);
{tcp_closed,S} ->
io:format("Socket ~w closed [~w]~n",[S,self()]),
ok
end.
这很好用:
servertest:start(1, 1241).
server started
1241
当我添加另一层 spawn
并且创建侦听套接字的代码启动接受服务器时,问题就开始了:
-module(servertest2).
%% API
-export([start/2, server/1, start_listening/2]).
start(Num,LPort) ->
erlang:spawn_link(?MODULE, start_listening, [Num,LPort]).
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),
Port;
{error,Reason} ->
{error,Reason}
end.
start_servers(0,_) ->
ok;
start_servers(Num,LS) ->
spawn(?MODULE,server,[LS]),
start_servers(Num-1,LS).
server(LS) ->
io:format("server started~n", []),
case gen_tcp:accept(LS) of
{ok,S} ->
loop(S),
server(LS);
Other ->
io:format("accept returned ~w - goodbye!~n",[Other]),
ok
end.
loop(S) ->
inet:setopts(S,[{active,once}]),
receive
{tcp,S,Data} ->
Answer = Data, % Not implemented in this example
gen_tcp:send(S,Answer),
loop(S);
{tcp_closed,S} ->
io:format("Socket ~w closed [~w]~n",[S,self()]),
ok
end.
当它像这样启动时,accept
立即(没有任何传入连接)returns {error,closed}
:
servertest2:start(1, 1242).
server started
<0.13452.0>
accept returned {error,closed} - goodbye!
为了澄清这里是两个版本之间的差异:
--- servertest.erl 2021-11-25 00:04:32.000000000 +0100
+++ servertest2.erl 2021-11-25 00:04:01.000000000 +0100
@@ -1,9 +1,12 @@
--module(servertest).
+-module(servertest2).
%% API
--export([start/2, server/1]).
+-export([start/2, server/1, start_listening/2]).
start(Num,LPort) ->
+ erlang:spawn_link(?MODULE, start_listening, [Num,LPort]).
+
+start_listening(Num,LPort) ->
case gen_tcp:listen(LPort,[{active, false},{packet,0}]) of
{ok, ListenSock} ->
start_servers(Num,ListenSock),
谢谢!
如果不进行测试,我会说在第二种情况下,作为侦听套接字所有者的进程在生成接受器后自然死亡,从而关闭侦听套接字。
调用start_servers
验证后添加一些timer:sleep
或receive
我运行遇到了一个st运行ge问题。我正在测试 docs 中的代码,该代码创建多个进程以接受来自侦听套接字的传入连接:
-module(servertest).
%% API
-export([start/2, server/1]).
start(Num,LPort) ->
case gen_tcp:listen(LPort,[{active, false},{packet,0}]) of
{ok, ListenSock} ->
start_servers(Num,ListenSock),
{ok, Port} = inet:port(ListenSock),
Port;
{error,Reason} ->
{error,Reason}
end.
start_servers(0,_) ->
ok;
start_servers(Num,LS) ->
spawn(?MODULE,server,[LS]),
start_servers(Num-1,LS).
server(LS) ->
io:format("server started~n", []),
case gen_tcp:accept(LS) of
{ok,S} ->
loop(S),
server(LS);
Other ->
io:format("accept returned ~w - goodbye!~n",[Other]),
ok
end.
loop(S) ->
inet:setopts(S,[{active,once}]),
receive
{tcp,S,Data} ->
Answer = Data, % Not implemented in this example
gen_tcp:send(S,Answer),
loop(S);
{tcp_closed,S} ->
io:format("Socket ~w closed [~w]~n",[S,self()]),
ok
end.
这很好用:
servertest:start(1, 1241).
server started
1241
当我添加另一层 spawn
并且创建侦听套接字的代码启动接受服务器时,问题就开始了:
-module(servertest2).
%% API
-export([start/2, server/1, start_listening/2]).
start(Num,LPort) ->
erlang:spawn_link(?MODULE, start_listening, [Num,LPort]).
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),
Port;
{error,Reason} ->
{error,Reason}
end.
start_servers(0,_) ->
ok;
start_servers(Num,LS) ->
spawn(?MODULE,server,[LS]),
start_servers(Num-1,LS).
server(LS) ->
io:format("server started~n", []),
case gen_tcp:accept(LS) of
{ok,S} ->
loop(S),
server(LS);
Other ->
io:format("accept returned ~w - goodbye!~n",[Other]),
ok
end.
loop(S) ->
inet:setopts(S,[{active,once}]),
receive
{tcp,S,Data} ->
Answer = Data, % Not implemented in this example
gen_tcp:send(S,Answer),
loop(S);
{tcp_closed,S} ->
io:format("Socket ~w closed [~w]~n",[S,self()]),
ok
end.
当它像这样启动时,accept
立即(没有任何传入连接)returns {error,closed}
:
servertest2:start(1, 1242).
server started
<0.13452.0>
accept returned {error,closed} - goodbye!
为了澄清这里是两个版本之间的差异:
--- servertest.erl 2021-11-25 00:04:32.000000000 +0100
+++ servertest2.erl 2021-11-25 00:04:01.000000000 +0100
@@ -1,9 +1,12 @@
--module(servertest).
+-module(servertest2).
%% API
--export([start/2, server/1]).
+-export([start/2, server/1, start_listening/2]).
start(Num,LPort) ->
+ erlang:spawn_link(?MODULE, start_listening, [Num,LPort]).
+
+start_listening(Num,LPort) ->
case gen_tcp:listen(LPort,[{active, false},{packet,0}]) of
{ok, ListenSock} ->
start_servers(Num,ListenSock),
谢谢!
如果不进行测试,我会说在第二种情况下,作为侦听套接字所有者的进程在生成接受器后自然死亡,从而关闭侦听套接字。
调用start_servers
验证后添加一些timer:sleep
或receive