0
votes

I'm trying to get a client (behind a NAT) to send packet to a dedicated server.

Here's my code :

-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.

on the dedicated server I launch the listen function :

# 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).

on the client side I launch the sending loop :

$ 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

Although gen_udp:send from the client returns ok, the server doesn't seems to receive any of these packets, as it should print "server received: "HELLO !!!"" on the console.

anyone would have an idea why this is not working.

EDIT 1 :

  • There is no firewall or iptable configured on the dedicated server.

  • The connection works fine through TCP between the client and the server, but not UDP.

  • When I try to run both server and client on the same device (different erlang node), it does not work either.

EDIT 2 : changed the code for the listen part looping on itself re-creating the Socket each time a message is received... but still does not work.

2
What is the actual value of "ip.to.my.server"? Have you tried it just using {127.0.0.1}? - rvirding
the ip "ip.to.my.server" is a string like this : "27.46.35.14"... Actually i should have called it "ip.of.my.server"... EDITED - TheSquad
And when I try to run the server and the client on the same machine... it does not work either, actually. - TheSquad
Aha, you're modified code is much easier to see why it doesn't work. I will edit my answer about it. - rvirding

2 Answers

2
votes

Your start_client/3, send/4 loop should work as expected, although it is a slightly convoluted way to get a 1 sec delay.

Your listen/1 will not do as expected and should at most return one message:

  • For each loop it opens a new socket, the first time it uses the port to open the socket while in the following loops it uses the socket to open a new socket, which should generate an error.
  • You set the socket to {active,once} so you will at most receive one packet on the socket before you reset it to being active once.

Why try on the receiving side doing something simple like:

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> 

as a first step to test the basic connection?

EDIT:

In your new version you call start_listen/1 which opens a UDP socket and then spawns a process to sit and listen on it. The process which opens the port is the ports controlling process. The messages sent when a packet arrives is sent to the controlling process, which in this case is not the controlling process.

There are two ways to fix this:

  • Spawn a process which first opens the port and and then goes into a loop receiving the UDP messages from the socket. This is how it is done in the example you referenced: start spawns a process running server which opens the port and then calls loop.

  • Use gen_udp:controlling_process/2 to pass control of the socket to the loop process so it will receive the packet messages.

Both work and have their place. You had the same structure in the original code but I missed it.

2
votes

Found the issue, I was starting the socket, then only spawning the loop...

Either change the controlling_process to the spawned pid, or open the socket on the spawned pid.

Hope it helps someone.