我正在尝试让客户端(在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:发送从客户端返回确定,但服务器似乎没有收到任何这些数据包,因为它应该打印“服务器收到:“HELLO !!!”“在控制台上。
任何人都会知道为什么这不起作用。
编辑1:
专用服务器上没有配置防火墙或iptable。
连接在客户端和服务器之间通过TCP正常工作,但不是UDP。
当我尝试在同一设备(不同的erlang节点)上运行服务器和客户端时,它也不起作用。
编辑2: 改变了listen部分的代码循环,每次收到消息时重新创建Socket ......但仍然无效。
答案 0 :(得分:2)
您的start_client/3
,send/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>
作为测试基本连接的第一步?
修改强>
在新版本中,您拨打start_listen/1
打开一个UDP套接字,然后会产生一个进程来坐下来听它。打开端口的过程是端口控制进程。数据包到达时发送的消息将发送到控制进程,在这种情况下,控制进程不是控制进程。
有两种方法可以解决这个问题:
产生一个进程,首先打开端口,然后进入一个从套接字接收UDP消息的循环。这是在您引用的示例中完成的:start
生成一个运行server
的进程,该进程打开端口,然后调用loop
。
使用gen_udp:controlling_process/2
将套接字的控制权传递给循环过程,以便它接收数据包消息。
既有工作又有自己的位置。您在原始代码中具有相同的结构,但我错过了它。
答案 1 :(得分:2)
发现问题,我正在启动套接字,然后才产生循环...
将controlling_process更改为生成的pid,或者在生成的pid上打开套接字。
希望它有所帮助。