Reputation: 755
I write a simple tcp server module and run it well. When i compile this module while running, the problem is that when the client send anything to server, it receives no response! How can fix it?
start(Port) ->
{ok, Listen} = gen_tcp:listen(Port, [{active, once}]),
spawn(?MODULE, loop, [Listen]).
loop(Listen) ->
{ok, Socket} = gen_tcp:accept(Listen),
spawn(?MODULE, loop, [Listen]),
handler(Socket).
handler(Socket) ->
receive
{tcp, Socket, Data} ->
%io:format("recv ~p~n", [Data]),
spawn(?MODULE, response, [self(), Data]),
inet:setopts(Socket, [{active, once}]),
handler(Socket);
{tcp_closed, Socket} ->
%io:format("disconnected~n", []),
gen_tcp:close(Socket);
{send_msg, Msg} ->
gen_tcp:send(Socket, lists:flatten(io_lib:format("~p", [Msg])) ++ ?END_CHAR),
handler(Socket)
end.
response(PID, Data) ->
[Req|Args] = string:tokens(Data, ?END_CHAR),
{ReqPID, ReqRef} = spawn_monitor(view, request, [list_to_atom(Req), self(), Args]),
receive
{'DOWN', ReqRef, process, ReqPID, {function_clause, _}} -> PID ! {send_msg, invalid_request};
{'DOWN', ReqRef, process, ReqPID, {{case_clause, _}, _}} -> PID ! {send_msg, bad_args};
{'DOWN', ReqRef, process, ReqPID, {{badmatch, _}, _}} -> PID ! {send_msg, bad_args};
Resp -> PID ! {send_msg, Resp}
end.
Upvotes: 0
Views: 51
Reputation: 20024
I recommend the following:
In your listen options, change {active,once}
to {active,false}
. You won't be receiving any messages on your listen socket, and you don't want any accepted sockets to inherit an active setting, as it's better to have them set an active setting when they're actually ready to deal with incoming messages.
In your handler/1
function, move the inet:setopts/2
call to the top, before the receive
. Also change it to check its return value, like this:
ok = inet:setopts(Socket, [{active, once}]),
I suspect you put it under the {tcp, ...}
message handling clause because technically it's needed only there, but having it at the top is less error-prone. It's also necessary since there's no active setting on the socket the first time handler/1
is called, given the first change I recommended above.
In your call to gen_tcp:send/2
, there is no need to flatten the list returned from io_lib:format
— it returns an iolist
, which gen_tcp:send/2
can handle just fine.
Upvotes: 2