Skip to content

Instantly share code, notes, and snippets.

@hryniuk
Forked from t4sk/a-usage.md
Created September 29, 2020 21:17
Show Gist options
  • Save hryniuk/fc6eb0f0d239f901acd601eb202215af to your computer and use it in GitHub Desktop.
Save hryniuk/fc6eb0f0d239f901acd601eb202215af to your computer and use it in GitHub Desktop.
gen_tcp and GenServer example in Elixir (1.5.2)

gen_tcp and GenServer example in Elixir (1.5.2)

Usage

server.ex

Server.start

Test the server

telnet 127.0.0.1 8000
> Hello World

client.ex

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment