首页 文章

未收到Erlang UDP数据包

提问于
浏览
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.

在专用服务器上我启动了listen功能:

# 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 !!!" ” .

任何人都会知道为什么这不起作用 .

EDIT 1 :

  • 专用服务器上未配置防火墙或iptable .

  • 连接在客户端和服务器之间通过TCP正常工作,但不是UDP .

  • 当我尝试在同一设备(不同的erlang节点)上运行服务器和客户端时,它也不起作用 .

EDIT 2 : 改变了listen部分的代码循环,每次收到消息时重新创建Socket ......但仍然不起作用 .

2 回答

  • 2

    您的 start_client/3send/4 循环应该按预期工作,尽管这是一种稍微复杂的方式来获得1秒的延迟 .

    您的 listen/1 将无法按预期执行,并且最多应返回一条消息:

    • 对于每个循环,它打开一个新套接字,第一次使用端口打开套接字,而在以下循环中,它使用套接字打开一个新套接字,这应该会产生错误 .

    • 您将套接字设置为 {active,once} ,因此在将其重置为活动一次之前,您最多将在套接字上接收一个数据包 .

    为什么尝试接收方做一些简单的事情:

    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>
    

    作为测试基本连接的第一步?

    EDIT:

    在您的新版本中,您调用 start_listen/1 打开一个UDP套接字, then 生成一个进程来坐下来听它 . 打开端口的过程是端口控制过程 . 数据包到达时发送的消息被发送到控制进程,在这种情况下,控制进程不是控制进程 .

    有两种方法可以解决这个问题:

    • 生成一个进程,该进程首先打开端口,然后进入从套接字接收UDP消息的循环 . 这是在您引用的示例中完成的: start 生成一个运行 server 的进程,该进程打开端口然后调用 loop .

    • 使用 gen_udp:controlling_process/2 将套接字的控制权传递给循环进程,以便它接收数据包消息 .

    两者都有效并且有自己的位置 . 您在原始代码中具有相同的结构,但我错过了它 .

  • 2

    发现问题,我正在启动套接字,然后才产生循环...

    将controlling_process更改为生成的pid,或者在生成的pid上打开套接字 .

    希望它可以帮助某人 .

相关问题