Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TCP Listener on Elixir using Erlang's gen_tcp module

Tags:

tcp

elixir

I am using the following code to create a TCP listener on elixir :

defmodule KVServer do
use Application

@doc false
def start(_type, _args) do
  import Supervisor.Spec

  children = [
    supervisor(Task.Supervisor, [[name: KVServer.TaskSupervisor]]),
    worker(Task, [KVServer, :accept, [4040]])
  ]

  opts = [strategy: :one_for_one, name: KVServer.Supervisor]
  Supervisor.start_link(children, opts)
end

@doc """
  Starts accepting connections on the given `port`.
"""
def accept(port) do
  {:ok, socket} = :gen_tcp.listen(port,
                  [:binary, packet: :line, active: false, reuseaddr:     true])
  IO.puts "Accepting connections on port #{port}"
  loop_acceptor(socket)
end

defp loop_acceptor(socket) do
  {:ok, client} = :gen_tcp.accept(socket)
  {:ok, pid} = Task.Supervisor.start_child(KVServer.TaskSupervisor, fn -> serve(client) end)
  :ok = :gen_tcp.controlling_process(client, pid)
  loop_acceptor(socket)
end

defp serve(socket) do
  socket
  |> read_line()
  |> write_line(socket)

  serve(socket)
end

defp read_line(socket) do
  {:ok, data} = :gen_tcp.recv(socket, 0)
  data
end

defp write_line(line, socket) do
  :gen_tcp.send(socket, line)
end
end

It is taken from the following link: http://elixir-lang.org/getting-started/mix-otp/task-and-gen-tcp.html

When I try to get data from my gps deveice (for which I am writing this piece of code) using :gen_tcp.recv(socket,0), I get an error: {:error, reason} = :gen_tcp.recv(socket, 0) and the reason it showed is just "closed".

However, the device is sending data, which I confirmed using a tcp packet sniffer (tcpflow).

Also, when I try to send data using telnet as described in the tutorial above, it works fine.

Any help would be highly appreciated.

like image 384
Kshitij Mittal Avatar asked Mar 14 '23 07:03

Kshitij Mittal


1 Answers

I was finally able to figure it out. Actually the device was sending raw stream of data not lines of data. So I had to change "packet: :line" parameter in :gen_tcp.listen function to "packet: :raw".

It was working on telnet because telnet sends lines of data (with line breaks).

like image 113
Kshitij Mittal Avatar answered Mar 25 '23 10:03

Kshitij Mittal