I can't get multiple clients to communicate with my concurrent echo server. Here are my results:
Server Terminal window:
1> c(s).
{ok,s}
2> s:init(15555).
Server started on port: 15555
Client Terminal window:
1> c(cl).
{ok,cl}
2> cl:test().
[<0.64.0>,<0.65.0>,<0.66.0>,<0.67.0>,<0.68.0>]
3>
=ERROR REPORT==== 21-May-2017::21:21:39 ===
Error in process <0.68.0> with exit value:
{{badmatch,{error,econnrefused}},[{cl,client,2,[{file,"cl.erl"},{line,5}]}]}
=ERROR REPORT==== 21-May-2017::21:21:39 ===
Error in process <0.67.0> with exit value:
{{badmatch,{error,econnrefused}},[{cl,client,2,[{file,"cl.erl"},{line,5}]}]}
...
...
In the shell, if I start my server, then connect one client, my client and server can communicate back and forth without error:
Server Terminal window:
1> c(s).
{ok,s}
2> s:init(15555).
Server started on port: 15555
Client Terminal window:
1> c(cl).
{ok,cl}
2> cl:client(1, 15555).
Client1: sent -->hello
Client1: received <--hello
ok
In my failing concurrent test, I do this:
test() ->
Port = 1555,
[spawn(?MODULE, client, [Id, Port]) || Id <- lists:seq(1, 5)].
Here's my echo server:
-module(s).
-compile(export_all).
init(Port) ->
{ok, ServerSocket} = gen_tcp:listen(Port, [binary, {active,true},
{packet,4}, {reuseaddr,true}] ),
io:format("Server started on port: ~w~n", [Port]),
server(ServerSocket).
server(ServerSocket) ->
{ok, ClientSocket} = gen_tcp:accept(ServerSocket),
spawn(?MODULE, server, [ServerSocket]),
timer:sleep(rand:uniform(3) * 1000),
loop(ClientSocket).
loop(ClientSocket) ->
receive
{tcp, ClientSocket, CompleteMsg} ->
io:format("Server: received ~s~n", [CompleteMsg]),
gen_tcp:send(ClientSocket, CompleteMsg);
{tcp_closed, ClientSocket} ->
io:format("Server: client closed socket.~n")
end,
loop(ClientSocket).
Here's my client:
-module(cl).
-compile(export_all).
client(Id, Port) ->
{ok, Socket} = gen_tcp:connect(localhost, Port, [binary, {active,true},
{packet,4},
{reuseaddr, true}] ),
Msg = "hello",
gen_tcp:send(Socket, Msg),
io:format("Client~w: sent -->~s~n", [Id, Msg]),
receive
{tcp, Socket, CompleteMsg} ->
io:format("Client~w: received <--~s~n", [Id, CompleteMsg]);
{tcp_closed, Socket} ->
io:format("Server closed the socket.~n")
end,
gen_tcp:close(Socket).
test() ->
Port = 1555,
[spawn(?MODULE, client, [Id, Port]) || Id <- lists:seq(1, 5)].
It's my understanding that a TCP socket
is nothing but a tuple containing four numbers:
{senderPort, senderAddress, destinationPort, destinationAddress}
I think that each of my clients must have the same senderPort
and senderAddress
, therefore they are all trying to use the same TCP socket. But I would think that one of my clients would be able to successfully establish a TCP connection while the rest got a connection refused error, yet all of my concurrent clients get a connection refused error.
It seems to me that gen_tcp:connect()
somehow picks a senderPort and retrieves the senderAddress, which along with the ServerAddress and ServerPort arguments, defines the socket. How can I make each of my clients use a different senderPort so that each client creates a unique socket?
Is there a way to programmatically test a concurrent server with multiple clients on localhost?