Server.start
Test the server
telnet 127.0.0.1 8000
> Hello World
Server.start
In another terminal
{:ok, pid} = Client.start
Client.send_message(pid, "Hello World")
| defmodule Client do | |
| require Logger | |
| use GenServer | |
| @ip {127, 0, 0, 1} | |
| @port 8000 | |
| def send_message(pid, message) do | |
| GenServer.cast(pid, {:message, message}) | |
| end | |
| def start do | |
| GenServer.start(__MODULE__, %{socket: nil}) | |
| end | |
| def init(state) do | |
| send(self(), :connect) | |
| {:ok, state} | |
| end | |
| def handle_info(:connect, state) do | |
| Logger.info "Connecting to #{:inet.ntoa(@ip)}:#{@port}" | |
| case :gen_tcp.connect(@ip, @port, [:binary, active: true]) do | |
| {:ok, socket} -> | |
| {:noreply, %{state | socket: socket}} | |
| {:error, reason} -> | |
| disconnect(state, reason) | |
| end | |
| end | |
| def handle_info({:tcp, _, data}, state) do | |
| Logger.info "Received #{data}" | |
| {:noreply, state} | |
| end | |
| def handle_info({:tcp_closed, _}, state), do: {:stop, :normal, state} | |
| def handle_info({:tcp_error, _}, state), do: {:stop, :normal, state} | |
| def handle_cast({:message, message}, %{socket: socket} = state) do | |
| Logger.info "Sending #{message}" | |
| :ok = :gen_tcp.send(socket, message) | |
| {:noreply, state} | |
| end | |
| def disconnect(state, reason) do | |
| Logger.info "Disconnected: #{reason}" | |
| {:stop, :normal, state} | |
| end | |
| end |
| defmodule Server do | |
| require Logger | |
| use GenServer | |
| @port 8000 | |
| def start do | |
| GenServer.start(__MODULE__, %{socket: nil}) | |
| end | |
| def init(state) do | |
| {:ok, socket} = :gen_tcp.listen(@port, [:binary, active: true]) | |
| send(self(), :accept) | |
| Logger.info "Accepting connection on port #{@port}..." | |
| {:ok, %{state | socket: socket}} | |
| end | |
| def handle_info(:accept, %{socket: socket} = state) do | |
| {:ok, _} = :gen_tcp.accept(socket) | |
| Logger.info "Client connected" | |
| {:noreply, state} | |
| end | |
| def handle_info({:tcp, socket, data}, state) do | |
| Logger.info "Received #{data}" | |
| Logger.info "Sending it back" | |
| :ok = :gen_tcp.send(socket, data) | |
| {:noreply, state} | |
| end | |
| def handle_info({:tcp_closed, _}, state), do: {:stop, :normal, state} | |
| def handle_info({:tcp_error, _}, state), do: {:stop, :normal, state} | |
| end |
@hryniuk
Your welcome. I am surprised this code is still useful
I got the same situation with one of my gists and I thought it would be good to say "thank you" :)
I've just started with Elixir and I was trying to do the client part. I did a loop with :gen_tcp.recv and wanted to switch to "active" socket, but around 95% of guides I've found were only about writing tcp servers. This code is exactly what I needed, thank you again for sharing. I'd definitely need a while to figure this out on my own.
@hryniuk Thanks for saying thanks 👍
Thanks, that's really helpful!