0

クライアント (NAT の背後) にパケットを専用サーバーに送信させようとしています。

これが私のコードです:

-module(udp_test).

-export([start_client/3, listen/1, send/4, start_listen/1]).

start_client(Host, Port, Packet) ->
    {ok, Socket} = gen_udp:open(0, [{active, true}, binary]),
    io:format("client opened socket=~p~n",[Socket]),
    spawn(?MODULE, send, [Socket, Host, Port, Packet]).

start_listen(Port) ->
    {ok, Socket} = gen_udp:open(Port, [binary]),
    spawn(?MODULE, listen, [Socket]).

listen(Socket) ->
    inet:setopts(Socket, [{active, once}]),
    receive
    {udp, Socket , Host, Port, Bin} ->
        gen_udp:send(Socket, Host, Port, "Got Message"),
        io:format("server received:~p / ~p~n",[Socket, Bin]),
        listen(Socket)
    end.

send(Socket, Host, Port, Packet) ->
    timer:send_after(1000, tryToSend),
    receive
    tryToSend ->
        io:fwrite("Sending: ~p / to ~p / P: ~p~n", [Packet, Host, Port]),
        Val = gen_udp:send(Socket, Host, Port, Packet),
        io:fwrite("Value: ~p~n", [Val]),
        send(Socket, Host, Port, Packet);
    _ ->
        io:fwrite("???~n")
    end.

専用サーバーでリッスン機能を起動します。

# erl -pa ebin
Erlang R15B01 (erts-5.9.1) [source] [64-bit] [smp:4:4] [async-threads:0] [kernel-poll:false]

Eshell V5.9.1  (abort with ^G)
1> udp_test:listen(4000).

クライアント側で、送信ループを起動します:

$ erl -pa ebin                                                      
Erlang R15B (erts-5.9) [source] [smp:2:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.9  (abort with ^G)
1> udp_test:start_client("ip.of.my.server", 4000, "HELLO !!!").
client opened socket=#Port<0.737>
<0.33.0>
Sending: "HELLO !!!" / to "ip.of.my.server" / P: 4000
Value: ok
Sending: "HELLO !!!" / to "ip.of.my.server" / P: 4000
Value: ok
Sending: "HELLO !!!" / to "ip.of.my.server" / P: 4000
Value: ok

クライアントからのgen_udp :sendはokを返しますが、コンソールに「 server received: "HELLO !!!" 」と出力する必要があるため、サーバーはこれらのパケットを受信して​​いないようです。

なぜこれが機能しないのか、誰もが考えているでしょう。

編集1:

  • 専用サーバーにファイアウォールや iptable が構成されていません。

  • 接続はクライアントとサーバー間の TCP を介して正常に機能しますが、UDP は機能しません。

  • サーバーとクライアントの両方を同じデバイス (別の erlang ノード) で実行しようとしても、どちらも機能しません。

EDIT 2 : メッセージを受信するたびにソケットを再作成することでループする listen 部分のコードを変更しましたが、それでも機能しません。

4

2 に答える 2

2

問題が見つかりました。ソケットを起動してから、ループを生成するだけでした...

Controlling_processをスポーンされたpidに変更するか、スポーンされたpidのソケットを開きます。

それが誰かを助けることを願っています。

于 2012-09-07T14:30:14.033 に答える
2

start_client/3,send/4ループは期待どおりに動作するはずですが、1 秒の遅延を得るには少し複雑な方法です。

期待どおりlisten/1に動作せず、多くても 1 つのメッセージを返す必要があります。

  • ループごとに新しいソケットを開きます。最初はポートを使用してソケットを開きますが、次のループではソケットを使用して新しいソケットを開きます。エラーが発生するはずです。
  • ソケットを に設定する{active,once}と、一度アクティブになるようにリセットする前に、ソケットで最大 1 つのパケットを受信するようになります。

受信側で次のような単純なことを試してみるのはなぜですか:

Erlang R15B (erts-5.9) [source] [smp:4:4] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.9  (abort with ^G)
1> {ok,S}=gen_udp:open(5555,[]).
{ok,#Port<0.582>}
2> flush().
Shell got {udp,#Port<0.582>,{127,0,0,1},4444,"hej"}
Shell got {udp,#Port<0.582>,{127,0,0,1},4444,"there"}
ok
3> 

基本的な接続をテストする最初のステップとして?

編集:

新しいバージョンstart_listen/1では、UDP ソケットを開き、それを待機してリッスンするプロセスを生成します。ポートを開くプロセスは、ポート制御プロセスです。パケットが到着したときに送信されるメッセージは、制御プロセスに送信されますが、この場合は制御プロセスではありません。

これを修正するには、次の 2 つの方法があります。

  • 最初にポートを開き、次にソケットから UDP メッセージを受信するループに入るプロセスを生成します。これは、参照した例での実行方法です。start実行中のプロセスを生成しserver、ポートを開き、 を呼び出しますloop

  • gen_udp:controlling_process/2ソケットの制御をループ プロセスに渡して、パケット メッセージを受信するために使用します。

どちらも機能し、自分の場所を持っています。元のコードでも同じ構造でしたが、見落としていました。

于 2012-09-07T13:07:37.840 に答える