lecture 06
This commit is contained in:
28 files changed
+825
No files matched your search
@@ -0,0 +1,144 @@
|
||||
defmodule Echo.Active do
|
||||
def start(port \\ 6666) do
|
||||
opts = [:binary, active: true, packet: :line, reuseaddr: true]
|
||||
{:ok, listen} = :gen_tcp.listen(port, opts)
|
||||
accept(listen)
|
||||
end
|
||||
|
||||
def accept(listen) do
|
||||
{:ok, socket} = :gen_tcp.accept(listen) # data delivered as messages in the mailbox of the
|
||||
# process that calls accept
|
||||
spawn(fn -> accept(listen) end)
|
||||
loop(socket)
|
||||
end
|
||||
|
||||
defp loop(socket) do
|
||||
receive do
|
||||
{:tcp, ^socket, data} ->
|
||||
:gen_tcp.send(socket, data)
|
||||
loop(socket)
|
||||
{:tcp_closed, ^socket} ->
|
||||
:gen_tcp.close(socket)
|
||||
{:tcp_error, ^socket, _reason} ->
|
||||
:gen_tcp.close(socket)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Echo.Passive do
|
||||
def start(port \\ 6666) do
|
||||
opts = [:binary, active: false, packet: :line, reuseaddr: true] # note: active: false
|
||||
{:ok, listen} = :gen_tcp.listen(port, opts)
|
||||
accept(listen)
|
||||
end
|
||||
|
||||
def accept(listen) do
|
||||
{:ok, socket} = :gen_tcp.accept(listen) # data delivered as messages in the mailbox of the
|
||||
# process that calls accept
|
||||
spawn(fn -> accept(listen) end)
|
||||
loop(socket)
|
||||
end
|
||||
|
||||
def loop(socket) do
|
||||
case :gen_tcp.recv(socket, 0) do
|
||||
{:ok, data} ->
|
||||
:gen_tcp.send(socket, data)
|
||||
loop(socket)
|
||||
{:error, _reason} ->
|
||||
:gen_tcp.close(socket)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Echo.Hybrid do
|
||||
def start(port \\ 6666) do
|
||||
opts = [:binary, active: :once, packet: :line, reuseaddr: true]
|
||||
{:ok, listen} = :gen_tcp.listen(port, opts)
|
||||
accept(listen)
|
||||
end
|
||||
|
||||
def accept(listen) do
|
||||
{:ok, socket} = :gen_tcp.accept(listen) # data delivered as messages in the mailbox of the
|
||||
# process that calls accept (the controlling process)
|
||||
spawn(fn -> accept(listen) end)
|
||||
loop(socket)
|
||||
end
|
||||
|
||||
defp loop(socket) do
|
||||
receive do
|
||||
{:tcp, ^socket, data} ->
|
||||
:inet.setopts(socket, active: :once)
|
||||
:gen_tcp.send(socket, data)
|
||||
loop(socket)
|
||||
{:tcp_closed, ^socket} ->
|
||||
:gen_tcp.close(socket)
|
||||
{:tcp_error, ^socket, _reason} ->
|
||||
:gen_tcp.close(socket)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Echo do
|
||||
use GenServer
|
||||
require Logger
|
||||
|
||||
def start(port \\ 6666) do
|
||||
GenServer.start(__MODULE__, port)
|
||||
end
|
||||
|
||||
@impl true
|
||||
def init(port) do
|
||||
opts = [:binary, active: true, packet: :line, reuseaddr: true]
|
||||
{:ok, listen} = :gen_tcp.listen(port, opts)
|
||||
send(self(), :accept)
|
||||
{:ok, listen}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info(:accept, listen) do
|
||||
{:ok, socket} = :gen_tcp.accept(listen)
|
||||
log(socket, "accepted connection")
|
||||
{:ok, pid} = Echo.Worker.start(socket)
|
||||
:gen_tcp.controlling_process(socket, pid)
|
||||
send(self(), :accept)
|
||||
{:noreply, listen}
|
||||
end
|
||||
|
||||
defp log(socket, msg) do
|
||||
Logger.info("#{inspect self()}: #{msg} #{inspect socket}")
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Echo.Worker do
|
||||
use GenServer
|
||||
require Logger
|
||||
|
||||
def start(socket) do
|
||||
GenServer.start(__MODULE__, socket)
|
||||
end
|
||||
|
||||
@impl true
|
||||
def init(socket) do
|
||||
log(socket, "started worker")
|
||||
{:ok, socket}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info({:tcp, socket, data}, socket) do
|
||||
:inet.setopts(socket, active: :once)
|
||||
:gen_tcp.send(socket, data)
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info({:tcp_closed, socket}, socket) do
|
||||
:gen_tcp.close(socket)
|
||||
log(socket, "closed connection")
|
||||
{:stop, :normal, socket}
|
||||
end
|
||||
|
||||
defp log(socket, msg) do
|
||||
Logger.info("#{inspect self()}: #{msg} #{inspect socket}")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
defmodule Echo.Client do
|
||||
def connect(host, port \\ 6666) do
|
||||
opts = [active: false, packet: :line]
|
||||
{:ok, socket} = :gen_tcp.connect(host, port, opts)
|
||||
loop(socket)
|
||||
end
|
||||
|
||||
defp loop(socket) do
|
||||
case IO.gets("> ") do
|
||||
:eof ->
|
||||
:gen_tcp.close(socket)
|
||||
line ->
|
||||
:gen_tcp.send(socket, line)
|
||||
case :gen_tcp.recv(socket, 0) do
|
||||
{:ok, data} ->
|
||||
IO.write(data)
|
||||
loop(socket)
|
||||
{:error, _} ->
|
||||
:gen_tcp.close(socket)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
with [host, port | _] <- System.argv(),
|
||||
{port, _} <- Integer.parse(port)
|
||||
do
|
||||
Echo.Client.connect(String.to_atom(host), port)
|
||||
else
|
||||
_ -> Echo.Client.connect(:"127.0.0.1", 6666)
|
||||
end
|
||||
Reference in new issue
Block a user