4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ElixirでTCPのサーバーとクライアントを試しに作成

Last updated at Posted at 2020-08-03

はじめに

Task and gen_tcpを読みながらやっても、TCPサーバーがうまく反応してくれなかったのですが、一応反応してくれたので残しておきます。

TCPサーバー

defmodule Tcp1 do
  @moduledoc """
  Tcp1 keeps the contexts that define your domain
  and business logic.

  Contexts are also responsible for managing your data, regardless
  if it comes from the database, an external API or others.
  """
  require Logger

  def accept(port) do
    {:ok, socket} = :gen_tcp.listen(port, [:binary, packet: 0, active: false, reuseaddr: true])
    Logger.info("Accepting connections on port #{port}")
    loop_acceptor(socket)
  end

  defp loop_acceptor(socket) do
    {:ok, client} = :gen_tcp.accept(socket)
    Logger.info("Connected")
    serve(client)
    loop_acceptor(socket)
  end

  defp serve(socket) do
    socket
    |> read()
    |> write(socket)

    serve(socket)
  end

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

  defp write(line, socket) do
    :ok = :gen_tcp.send(socket, line)
  end
end

この行に変更を加えてあります。↓

{:ok, socket} = :gen_tcp.listen(port, [:binary, packet: 0, active: false, reuseaddr: true])

もともとはpacket: :lineと書いてあったのですが、そのままだと動きませんでした。
クライアントから送られてくるデータが1行ずつ送信されてくるとかではなく、生のデータとして送信されているからのようです。
なので、packet: 0もしくはpacket: :rawというふうに変更したら動きました。
※Line-Basedなプロトコル(\rとか\nで区切られてるようなやつ)を扱うときはちゃんと:lineと指定してあげないとだめなようです。

TCPクライアント

defmodule Tcp2 do
  @moduledoc """
  Tcp2 keeps the contexts that define your domain
  and business logic.

  Contexts are also responsible for managing your data, regardless
  if it comes from the database, an external API or others.
  """

  require Logger

  @msg "msg from me"

  def connect() do
    {:ok, socket} = :gen_tcp.connect('localhost', 4040, [:binary, active: false])
    send_messages(socket)
  end

  defp send_messages(socket) do
    :timer.sleep(1000)
    :ok = :gen_tcp.send(socket, @msg)
    Logger.info(@msg)
    {:ok, _data} = :gen_tcp.recv(socket, 0)
    send_messages(socket)
  end
end

1秒経つごとに、"msg from me"というデータを接続先のサーバーに送信してくれます。

さいごに

とりあえず試しに動くようなものができました。
:lineとか:rawとかそのへんはまた実装していく上で調べながら注意していこうと思います。

参考リンク

https://elixirforum.com/t/i-can-connect-using-gen-tcp-but-i-cant-send-receive-data-what-is-wrong-with-this-implementation/6487/4
https://www.boost.org/doc/libs/1_35_0/doc/html/boost_asio/design/line_based.html

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?