Принятый сокет от задачи, терпящей неудачу в другом процессе

Я пытаюсь протестировать некоторый код эликсира и натолкнулся на поведение gen_tcp, которое я не понимаю. Когда я генерирую gen_tcp.accept сокет, я могу "получить к нему доступ" в задаче, в которой я его создал, но не в другом. Я решил, что это проблема "control_process", но даже когда я добавил, что любая попытка использовать: inet.getstat приводит к ошибке неверного аргумента. Эликсир утверждает, что он также закрыт, но для этого вопроса получить проще было. Увидеть ниже:

defmodule ElixirQuestion do
  def serve_one_client(socket, pid) 
  do  
    {:ok, server_socket} = :gen_tcp.accept(socket)
    :ok = :gen_tcp.controlling_process(server_socket, pid)
    IO.inspect(:inet.getstat(server_socket))
    server_socket 
  end 
end

{:ok, socket} = :gen_tcp.listen(0, [:binary, 
                                      {:packet, :raw}, 
                                      {:active, false}])
{:ok, port_number} = :inet.port(socket)
server_task = Task.async(fn -> ElixirQuestion.serve_one_client(socket, self()) end)
{:ok, _client_socket} = :gen_tcp.connect('localhost', port_number, [active: false]) 
server_socket = Task.await(server_task)

IO.inspect(:inet.getstat(server_socket))

Ожидаемый результат

{:ok,
 [recv_oct: 0, recv_cnt: 0, recv_max: 0, recv_avg: 0, recv_dvi: 0, send_oct: 0,
  send_cnt: 0, send_max: 0, send_avg: 0, send_pend: 0]}
{:ok,
 [recv_oct: 0, recv_cnt: 0, recv_max: 0, recv_avg: 0, recv_dvi: 0, send_oct: 0,
  send_cnt: 0, send_max: 0, send_avg: 0, send_pend: 0]}

Полученный вывод

{:ok,
 [recv_oct: 0, recv_cnt: 0, recv_max: 0, recv_avg: 0, recv_dvi: 0, send_oct: 0,
  send_cnt: 0, send_max: 0, send_avg: 0, send_pend: 0]}
{:error, :einval}

Версия эликсира

Erlang/OTP 19 [erts-8.3.5.3] [source] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false]

Elixir 1.4.5

1 ответ

Решение

self() внутри Task.async вернет PID Task процесс. Так как здесь вам нужно значение родительского процесса, вам нужно сохранить это значение вне fn, переданного в Task.async а затем использовать это внутри.

Изменение:

server_task = Task.async(fn -> ElixirQuestion.serve_one_client(socket, self()) end)

чтобы:

me = self()
server_task = Task.async(fn -> ElixirQuestion.serve_one_client(socket, me) end)

дает мне результат, который вы ожидаете:

{:ok,
 [recv_oct: 0, recv_cnt: 0, recv_max: 0, recv_avg: 0, recv_dvi: 0, send_oct: 0,
  send_cnt: 0, send_max: 0, send_avg: 0, send_pend: 0]}
{:ok,
 [recv_oct: 0, recv_cnt: 0, recv_max: 0, recv_avg: 0, recv_dvi: 0, send_oct: 0,
  send_cnt: 0, send_max: 0, send_avg: 0, send_pend: 0]}
Другие вопросы по тегам