Koszal

Koszal

Protohackers in Elixir - day 0

I followed a tutorial and created a gen_tcp server. The code is shown below. The server accepts connections, receives data but the function recv_until_closed (at the very bottom) never matches on {:error, :closed}. Consequently, the connections are never closed. Instead I eventually get timeout errors. I’m testing it by echoing a string to nc localhost 5001 as shown in the video (around 17:30)

This is the first video in the Photohackers in Elixir series

Is there some obvious error in my code that I’m failing to see?

defmodule EventListener.Server do
  use GenServer
  require Logger

  def start_link([] = _opts) do
    GenServer.start_link(__MODULE__, :no_state)
  end

  defstruct [:listen_socket]

  @impl true
  def init(:no_state) do

    listen_options = [
      ifaddr: {0, 0, 0, 0},
      mode: :binary,
      active: false,
      reuseaddr: true,
      exit_on_close: false
    ]

    case :gen_tcp.listen(5001, listen_options) do
      {:ok, listen_socket} ->

        state = %__MODULE__{listen_socket: listen_socket}
        {:ok, state, {:continue, :accept}}

      {:error, reason} ->
        {:stop, reason}
    end
  end

  @impl true
  def handle_continue(:accept, %__MODULE__{} = state) do
    case :gen_tcp.accept(state.listen_socket) do
      {:ok, socket} ->
        handle_connection(socket)
        {:noreply, state, {:continue, :accept}}
      {:error, reason} ->
        {:stop, reason}
    end
  end

  defp handle_connection(socket) do
    case recv_until_closed(socket, _buffer = "") do
      {:ok, data} -> 
        :gen_tcp.send(socket, data)
      {:error, reason} ->
        Logger.error("Failed to receive data: #{inspect(reason)}");
    end

    :gen_tcp.close(socket)
  end

  defp recv_until_closed(socket, buffer) do
    case :gen_tcp.recv(socket, 0, 10_000) do
      {:ok, data} -> 
        recv_until_closed(socket, [buffer, data])
      {:error, :closed} -> 
        {:ok, buffer} 
      {:error, reason} -> {:error, reason}
    end
  end
end

First 2 of 2 Posts Switch mode

Koszal

Koszal OP

I’m testing it by echoing a string to nc localhost 5001 as shown in the video

-N helps. From man nc:

-N
shutdown(2) the network socket after EOF on the input. Some servers require this to finish their work.

trisolaran

trisolaran

nevermind :slight_smile:

— All posts loaded —

Where Next?

Trending in Challenges Top

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve. They are GUI (Emerge) and State management (S...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
type1fool
I just stumbled on a newly redesigned elixir-lang.org. :tada: It looks like @Software_Mansion did the work, and I think it is generally a...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New

We're in Beta

About us Mission Statement