Always get timeout on :gen_tcp.accept/2

Behold, the following boilerplate code for opening a TCP socket with random port:

{:ok, server} = :gen_tcp.listen 0, [:binary, {:active, false}, {:packet, 0}]
{:ok, port} = :inet.port server
{:ok, socket} = :gen_tcp.accept server, 1000

My problem, is that this always times out on :gen_tcp.accept/2

iex(2)> {:ok, socket} = :gen_tcp.accept server, 1000
** (MatchError) no match of right hand side value: {:error, :timeout}

I’m wondering why I can’t seem to get this simple TCP server to accept connections? I was thinking that maybe there’s some option I need to specify to :gen_tcp.listen, but I haven’t had any luck trying different options out.

What’s even crazier is that https://github.com/LeeroyDing/json_logger/blob/master/test/json_logger_tcp_test.exs contains a test with such a TCP server, and when I run the tests, it passes, whoever when I in iex try to replicate the :gen_tcp calls, I get the above timeout. What am I missing?

1 Like

Are you sure you are getting a connection request to the listen socket (server) within the accept 1000 msec timeout? The return value {:error,:timeout} suggests that you are not.

1 Like

I never get any response from accept/2 regardless of timeout value, it either times out or waits forever.

Are you trying to connect to the server socket? If so how?

This was the key - if I connecting to the server before trying to create a listener, it’s now working as expected.

iex(7)> opts = [mode: :binary, active: false, packet: 0, keepalive: true]
[mode: :binary, active: false, packet: 0, keepalive: true]
iex(8)> {:ok, server} = :gen_tcp.listen 0, opts
{:ok, #Port<0.1280>}
iex(9)> {:ok, port} = :inet.port server
{:ok, 56261}
iex(10)> {:ok, socket} = :gen_tcp.connect('localhost', port, opts, 1000)
{:ok, #Port<0.1281>}
iex(11)> {:ok, listener} = :gen_tcp.accept server, 1000
{:ok, #Port<0.1282>}
iex(12)> :gen_tcp.send(socket, "hi")
:ok
iex(13)> :gen_tcp.recv(listener, 0, 1000)
{:ok, "hi"}
1 Like

You will get a better feel for how it works if you don’t do everything directly in the shell but use processes. Create a separate process which does listen, then accept and then recv, then prints the message and then terminates. Start that process then in the shell connect to the socket and send it a message.

This is closer to the real world usage.

1 Like

Will try that, thanks for the help! :slight_smile:

1 Like