4

I modified this server to use gen_tcp:recv inorder to limit the number of bytes for a packet to 50. I commented out the line inet:setopts(Socket, [{active, once}]), because gen_tcp:recv is supposed to be {active,false}. This is the client side erl shell

2> cp3:client().
exit
3> 

and this is the server side erl shell

4> cp3:server().
Started Server:
<0.46.0>
Accept Server:
Pid <0.48.0>
Connection accepted 
Accept Server:
Loop Server:
5> 

I also wondered how can I know if the socket closed with the return value {tcp_closed, Socket} if gen_tcp:recv doesn't create one?

-module(cp3).
-export([client/0, server/0,start/0,accept/1,enter_loop/1,loop/1]).

client() ->
    {ok, Socket} =  gen_tcp:connect("localhost", 4001,[list, {packet, 0}]),
    ok = gen_tcp:send(Socket, "packet"),
    receive
        {tcp,Socket,String} ->
            io:format("Client received = ~p~n",[String]),       
            io:format("Client result = ~p~n",[String]),
            gen_tcp:close(Socket)
        after 1000 ->
            exit        
    end.

server() -> 
    Pid = spawn(fun()-> start() end),
    Pid.

start() ->  
    io:format("Started Server:~n"),
    {ok, Socket} = gen_tcp:listen(4001, [binary, {packet, 0},{reuseaddr, true},{active, false}]),
    accept(Socket).

accept(ListenSocket) ->
    io:format("Accept Server:~n"),
    case gen_tcp:accept(ListenSocket) of
        {ok, Socket} ->
            Pid = spawn(fun() ->
                io:format("Connection accepted ~n", []),
                enter_loop(Socket)
            end),
            io:format("Pid ~p~n",[Pid]),
            gen_tcp:controlling_process(Socket, Pid),
            Pid ! ack,
            accept(ListenSocket);
        Error ->
            exit(Error)
    end.

enter_loop(Socket) ->
    %% make sure to acknowledge owner rights transmission finished
    receive ack -> ok end,
    loop(Socket).

loop(Socket) ->
    %% set socket options to receive messages directly into itself
    %%inet:setopts(Socket, [{active, once}]),
    io:format("Loop Server:~n"),
    case gen_tcp:recv(Socket, 50) of
    {ok, Data} ->  
        case Data of
            <<"packet">> ->                 
                io:format("Server replying = ~p~n",[Data]),   
                gen_tcp:send(Socket, Data),
                loop(Socket)                  
        end;
    {error, Reason} ->      
        io:format("Error on socket ~p reason: ~p~n", [Socket, Reason])          
    end.
Community
  • 1
  • 1
pandoragami
  • 5,387
  • 15
  • 68
  • 116
  • I'm sorry I don't quite understand your question. In an active socket the controlling process will be sent a `{tcp_closed,Socket}` message when the socket closes while for a passive socket calling `gen_tcp:recv` will return `{error,closed}`. The "*activeness*" is set for each end and can be difference. How it is handled if the other end of a socket outside Erlang is irrelevant. – rvirding Mar 25 '13 at 11:48
  • Ok I also have one other question, is this a parallel server meaning that it spawns a new process for each client connected? – pandoragami Mar 25 '13 at 19:04
  • Yes it does. The function `accept/1` sits in a recursive loop. It calls `gen_tcp:accept` and when it returns a new data socket it spawns a new process which runs `enter_loop/1` on that connection. It then hands over control of the socket, the call to `gen_tcp:controlling_process/2`, then calls it self recursively to wait for a new connection ofr which it spawn a new process to handle, etc. This proceeds until `gen_tcp:accept` returns an error and the function terminates. This is a common way of creating a new process for each connection. – rvirding Mar 26 '13 at 07:00

1 Answers1

4

I am not very clear about your question, but the above code does not work. Hope the following answers your problem. Your tcp receive case gen_tcp:recv(Socket, 50) of has one error. It is waiting for 50 bytes to read. Check the documentation of gen_tcp:recv/2. Change the length (length of packer 6 but preferably to) 0 to receive all the bytes.

The value does not limit the size of data, but it will not send the data back until it receives data of length 50. Instead you may need to accept and then check it.

Vinod
  • 2,243
  • 14
  • 18
  • You're right and that is what I needed its just Erlangs' documentation is terribly explained and I thought that any packet over the limit set in `recv` becomes discarded, nowhere did I notice an explanation that nothing will be sent back to the client. – pandoragami Mar 25 '13 at 18:32