Why this code not being infinite recursive?

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Why this code not being infinite recursive?

I Gusti Ngurah Oka Prinarjaya
Hi,

I learn gen_tcp from learnyousomeerlangg book. I try to understand flow of code below. 
And i got confused with acceptor/1 . Because acceptor/1 call itself but have no base case and just execute once. It's not usual. Why? 
From my understanding it should be an infinity recursive.

-module(naive_tcp).
-compile(export_all).

start_server(Port) ->
  Pid = spawn_link(
    fun() ->
      io:format("Spawned at start_server()~n"),
      {ok, ListenSocket} = gen_tcp:listen(Port, [binary, {active, false}]),
      spawn(fun() -> acceptor(ListenSocket) end),
      timer:sleep(infinity)
    end
  ),
  {ok, Pid}.

acceptor(ListenSocket) ->
  io:format("I am acceptor~n"),
  {ok, AcceptorSocket} = gen_tcp:accept(ListenSocket),
  spawn(fun() -> acceptor(ListenSocket) end),
  handle(AcceptorSocket).

handle(AcceptorSocket) ->
  inet:setopts(AcceptorSocket, [{active, once}]),
  receive
    {tcp, AcceptorSocket, <<"quit", _/binary>>} ->
      gen_tcp:close(AcceptorSocket);
    {tcp, AcceptorSocket, Message} ->
      gen_tcp:send(AcceptorSocket, Message),
      handle(AcceptorSocket)
  end.


Please enlightenment 

Thank you 



_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
by
Reply | Threaded
Open this post in threaded view
|

Re: Why this code not being infinite recursive?

by
Hi,

The acceptor is waiting for new TCP connection.
If a new connection arrives, it will spawn a new process waiting for future new connection first, then the current process will handle communication on the connected connection.

Best Regards,
Yao

在 2019年6月14日,12:45,I Gusti Ngurah Oka Prinarjaya <[hidden email]> 写道:

Hi,

I learn gen_tcp from learnyousomeerlangg book. I try to understand flow of code below. 
And i got confused with acceptor/1 . Because acceptor/1 call itself but have no base case and just execute once. It's not usual. Why? 
From my understanding it should be an infinity recursive.

-module(naive_tcp).
-compile(export_all).

start_server(Port) ->
  Pid = spawn_link(
    fun() ->
      io:format("Spawned at start_server()~n"),
      {ok, ListenSocket} = gen_tcp:listen(Port, [binary, {active, false}]),
      spawn(fun() -> acceptor(ListenSocket) end),
      timer:sleep(infinity)
    end
  ),
  {ok, Pid}.

acceptor(ListenSocket) ->
  io:format("I am acceptor~n"),
  {ok, AcceptorSocket} = gen_tcp:accept(ListenSocket),
  spawn(fun() -> acceptor(ListenSocket) end),
  handle(AcceptorSocket).

handle(AcceptorSocket) ->
  inet:setopts(AcceptorSocket, [{active, once}]),
  receive
    {tcp, AcceptorSocket, <<"quit", _/binary>>} ->
      gen_tcp:close(AcceptorSocket);
    {tcp, AcceptorSocket, Message} ->
      gen_tcp:send(AcceptorSocket, Message),
      handle(AcceptorSocket)
  end.


Please enlightenment 

Thank you 


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Why this code not being infinite recursive?

I Gusti Ngurah Oka Prinarjaya
In reply to this post by I Gusti Ngurah Oka Prinarjaya
Hi,

OMG. Finally..... I know and understand how this code flowing. It takes days for me to understand. 
It turns out this code below:

{ok, AcceptorSocket} = gen_tcp:accept(ListenSocket),

is locking / blocking the execution of these lines:

1. spawn(fun() -> acceptor(ListenSocket) end),
2. handle(AcceptorSocket).

Then, after we doing a connection to the port via telnet, the locking / blocking become released / unlocked / unblocked, then executing lines: 1 and  create new process,
lines: 2 listen / waiting the incoming message. Then make a new locking at the new created process for the next telnet connection. Yes this is an infinity recursive. 
The base case is killing main process that started from start_server/1 . exit(Pid, killed)

Thank you :)




Pada tanggal Jum, 14 Jun 2019 pukul 11.45 I Gusti Ngurah Oka Prinarjaya <[hidden email]> menulis:
Hi,

I learn gen_tcp from learnyousomeerlangg book. I try to understand flow of code below. 
And i got confused with acceptor/1 . Because acceptor/1 call itself but have no base case and just execute once. It's not usual. Why? 
From my understanding it should be an infinity recursive.

-module(naive_tcp).
-compile(export_all).

start_server(Port) ->
  Pid = spawn_link(
    fun() ->
      io:format("Spawned at start_server()~n"),
      {ok, ListenSocket} = gen_tcp:listen(Port, [binary, {active, false}]),
      spawn(fun() -> acceptor(ListenSocket) end),
      timer:sleep(infinity)
    end
  ),
  {ok, Pid}.

acceptor(ListenSocket) ->
  io:format("I am acceptor~n"),
  {ok, AcceptorSocket} = gen_tcp:accept(ListenSocket),
  spawn(fun() -> acceptor(ListenSocket) end),
  handle(AcceptorSocket).

handle(AcceptorSocket) ->
  inet:setopts(AcceptorSocket, [{active, once}]),
  receive
    {tcp, AcceptorSocket, <<"quit", _/binary>>} ->
      gen_tcp:close(AcceptorSocket);
    {tcp, AcceptorSocket, Message} ->
      gen_tcp:send(AcceptorSocket, Message),
      handle(AcceptorSocket)
  end.


Please enlightenment 

Thank you 



_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Why this code not being infinite recursive?

Artie Gold
But, wait! Infinite (well, unbounded) recursion is a bad thing, right? At the very least it will blow up the stack, right?

Well, yes. It would. Except for tail recursion. When the recursive step is at the end of the function (and there's no lingering state to maintain), the compiler can optimize the recursion into a simple loop. As a result you get the cleanliness of recursive solution without having to worry about the space needed by the calculation being unbounded. 

Cheers,
--ag

On Mon, Jun 17, 2019 at 11:06 AM I Gusti Ngurah Oka Prinarjaya <[hidden email]> wrote:
Hi,

OMG. Finally..... I know and understand how this code flowing. It takes days for me to understand. 
It turns out this code below:

{ok, AcceptorSocket} = gen_tcp:accept(ListenSocket),

is locking / blocking the execution of these lines:

1. spawn(fun() -> acceptor(ListenSocket) end),
2. handle(AcceptorSocket).

Then, after we doing a connection to the port via telnet, the locking / blocking become released / unlocked / unblocked, then executing lines: 1 and  create new process,
lines: 2 listen / waiting the incoming message. Then make a new locking at the new created process for the next telnet connection. Yes this is an infinity recursive. 
The base case is killing main process that started from start_server/1 . exit(Pid, killed)

Thank you :)




Pada tanggal Jum, 14 Jun 2019 pukul 11.45 I Gusti Ngurah Oka Prinarjaya <[hidden email]> menulis:
Hi,

I learn gen_tcp from learnyousomeerlangg book. I try to understand flow of code below. 
And i got confused with acceptor/1 . Because acceptor/1 call itself but have no base case and just execute once. It's not usual. Why? 
From my understanding it should be an infinity recursive.

-module(naive_tcp).
-compile(export_all).

start_server(Port) ->
  Pid = spawn_link(
    fun() ->
      io:format("Spawned at start_server()~n"),
      {ok, ListenSocket} = gen_tcp:listen(Port, [binary, {active, false}]),
      spawn(fun() -> acceptor(ListenSocket) end),
      timer:sleep(infinity)
    end
  ),
  {ok, Pid}.

acceptor(ListenSocket) ->
  io:format("I am acceptor~n"),
  {ok, AcceptorSocket} = gen_tcp:accept(ListenSocket),
  spawn(fun() -> acceptor(ListenSocket) end),
  handle(AcceptorSocket).

handle(AcceptorSocket) ->
  inet:setopts(AcceptorSocket, [{active, once}]),
  receive
    {tcp, AcceptorSocket, <<"quit", _/binary>>} ->
      gen_tcp:close(AcceptorSocket);
    {tcp, AcceptorSocket, Message} ->
      gen_tcp:send(AcceptorSocket, Message),
      handle(AcceptorSocket)
  end.


Please enlightenment 

Thank you 


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


--
Artie Gold, Austin, Texas
--
http://makeitsimpler.org

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Why this code not being infinite recursive?

I Gusti Ngurah Oka Prinarjaya
Hi Artie Gold,

Thank you for the additional information about this. 
what i do is just for learning purpose. So many syntax variation that i haven't understand yet.

Thank you


Pada tanggal Sen, 17 Jun 2019 pukul 23.45 Artie Gold <[hidden email]> menulis:
But, wait! Infinite (well, unbounded) recursion is a bad thing, right? At the very least it will blow up the stack, right?

Well, yes. It would. Except for tail recursion. When the recursive step is at the end of the function (and there's no lingering state to maintain), the compiler can optimize the recursion into a simple loop. As a result you get the cleanliness of recursive solution without having to worry about the space needed by the calculation being unbounded. 

Cheers,
--ag

On Mon, Jun 17, 2019 at 11:06 AM I Gusti Ngurah Oka Prinarjaya <[hidden email]> wrote:
Hi,

OMG. Finally..... I know and understand how this code flowing. It takes days for me to understand. 
It turns out this code below:

{ok, AcceptorSocket} = gen_tcp:accept(ListenSocket),

is locking / blocking the execution of these lines:

1. spawn(fun() -> acceptor(ListenSocket) end),
2. handle(AcceptorSocket).

Then, after we doing a connection to the port via telnet, the locking / blocking become released / unlocked / unblocked, then executing lines: 1 and  create new process,
lines: 2 listen / waiting the incoming message. Then make a new locking at the new created process for the next telnet connection. Yes this is an infinity recursive. 
The base case is killing main process that started from start_server/1 . exit(Pid, killed)

Thank you :)




Pada tanggal Jum, 14 Jun 2019 pukul 11.45 I Gusti Ngurah Oka Prinarjaya <[hidden email]> menulis:
Hi,

I learn gen_tcp from learnyousomeerlangg book. I try to understand flow of code below. 
And i got confused with acceptor/1 . Because acceptor/1 call itself but have no base case and just execute once. It's not usual. Why? 
From my understanding it should be an infinity recursive.

-module(naive_tcp).
-compile(export_all).

start_server(Port) ->
  Pid = spawn_link(
    fun() ->
      io:format("Spawned at start_server()~n"),
      {ok, ListenSocket} = gen_tcp:listen(Port, [binary, {active, false}]),
      spawn(fun() -> acceptor(ListenSocket) end),
      timer:sleep(infinity)
    end
  ),
  {ok, Pid}.

acceptor(ListenSocket) ->
  io:format("I am acceptor~n"),
  {ok, AcceptorSocket} = gen_tcp:accept(ListenSocket),
  spawn(fun() -> acceptor(ListenSocket) end),
  handle(AcceptorSocket).

handle(AcceptorSocket) ->
  inet:setopts(AcceptorSocket, [{active, once}]),
  receive
    {tcp, AcceptorSocket, <<"quit", _/binary>>} ->
      gen_tcp:close(AcceptorSocket);
    {tcp, AcceptorSocket, Message} ->
      gen_tcp:send(AcceptorSocket, Message),
      handle(AcceptorSocket)
  end.


Please enlightenment 

Thank you 


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


--
Artie Gold, Austin, Texas
--
http://makeitsimpler.org

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions