0

gen_tcp:accept が常に {error, closed} 応答を返す理由を特定するのに苦労しています。

基本的に、リッスン ソケットを作成するスーパーバイザがあります。

gen_tcp:listen(8081, [binary, {packet, 0}, {active, false}, {reuseaddr, true}]),

このソケットは、gen_server 動作の実装である子に渡されます。次に、子はソケットで接続を受け入れます。

accept(ListeningSocket, {ok, Socket}) ->                                   
    spawn(fun() -> loop(Socket) end),                                      
    accept(ListeningSocket);
accept(_ListeningSocket, {error, Error}) ->
    io:format("Unable to listen on socket: ~p.~n", [Error]),
    gen_server:call(self(), stop).

accept(ListeningSocket) ->                                                 
    accept(ListeningSocket, gen_tcp:accept(ListeningSocket)).                                                                                             

loop(Socket) ->                                                            
    case gen_tcp:recv(Socket, 0) of                                        
        {ok, Data} ->                                                      
            io:format("~p~n", [Data]),                                     
            process_request(Data),                                         
            gen_tcp:send(Socket, Data),                                    
            loop(Socket);                                                  
        {error, closed} -> ok                                              
   end.

スーパーバイザーと gen_server の BEAM バイナリをローカルにロードし、code:load_binary への RPC 呼び出しを介して別のノード (同じマシン上で実行) にロードします。次に、RPC 呼び出しを介してスーパーバイザーを実行します。これにより、サーバーが起動します。{error, closed} は、このシナリオでは常に gen_tcp:accept によって返されます。

ノード シェルにログインしているときにスーパーバイザとサーバを実行すると、サーバは問題なく接続を受け入れることができます。これには、接続を受け入れることができないリモート ノードへの「remsh」が含まれます。

シェルのみを使用して問題を再現できるようです。

[Terminal 1]: erl -sname node -setcookie abc -distributed -noshell

[Terminal 2]: erl -sname rpc -setcookie abc:

              net_adm:ping('node@verne').
              {ok, ListeningSocket} = rpc:call('node@verne', gen_tcp, listen, [8081, [binary, {packet, 0}, {active, true}, {reuseaddr, true}]]).
              rpc:call('node@verne', gen_tcp, accept, [ListeningSocket]).

最終 RPC への応答は {error, closed} です。

これは、ソケット/ポートの所有権と関係がありますか?

参考までに、接続を待機しているクライアントはなく、タイムアウトはどこにも設定していません。

4

1 に答える 1

2

それぞれrpc:callがターゲットノードで新しいプロセスを開始して、リクエストを処理します。最後の例では、最初の呼び出しでそのようなプロセス内にリッスン ソケットが作成され、そのプロセスが rpc 呼び出しの最後で終了すると、ソケットが閉じられます。したがって、受け入れを試行する 2 番目の rpc 呼び出しは、リッスン ソケットが既に閉じられているために失敗します。

あなたのデザインはいくつかの点で奇抜に見えます。たとえば、スーパーバイザーがソケットを開くのは正常ではありません。また、子はgen_serverまだ、手動recvループを示しているとも言いますが、これを実行するgen_serverとブロックされます。代わりに、何を達成しようとしているのかを説明し、目標を達成するための設計を考え出す際に助けを求めることができます。

于 2015-07-03T11:06:41.187 に答える