简体   繁体   中英

“Address in use” error when trying to UPD broadcast from Erlang / Elixir

In order for nodes to find the master node on my local area network, I get the master node to broadcast a message (with it's IP address). It's working with Python, no problem, but with Elixir I get an "address in use error" when trying to open a broadcast socket. Herewith some Python code that works:

udplisten.py:

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('', 8477))
while True:
    msg = s.recvfrom(1024)
    print(msg)

udpsend.py:

import socket 
import time
from datetime import datetime

cs = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
cs.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
cs.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
while True:
    cs.sendto(str(datetime.utcnow()).encode(), ('255.255.255.255', 8477)) # broadcast my address!  
    time.sleep(0.5)

So udpsend.py simply broadcasts a time string on port 8477 and udplisten.py prints whatever it gets. There is no port "address in use" conflict when running this code, no matter which of the two programs is started first.

Now if I run udplisten.py and then try to open a UDP socket in Elixir:

tbrowne@calculon:~/Dropbox/code/elixir/xxmaster/lib/priv$ iex
Erlang/OTP 20 [erts-9.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:10] [hipe] [kernel-poll:false]

Interactive Elixir (1.5.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> {:ok, sock} = :gen_udp.open(8477, [broadcast: true, reuseaddr: true])
** (MatchError) no match of right hand side value: {:error, :eaddrinuse}

I get the :error tuple with :eaddrinuse.

Note that I do not get this if udplisten.py is not running:

iex(1)> {:ok, sock} = :gen_udp.open(8477, [broadcast: true, reuseaddr: true])
{:ok, #Port<0.1291>}
iex(2)> 

However now my udplisten.py will not work:

tbrowne@calculon:~/Dropbox/code/elixir/xxmaster/lib/priv$ python udplisten.py
Traceback (most recent call last):
  File "udplisten.py", line 3, in <module>
    s.bind(('', 8477))
OSError: [Errno 98] Address already in use

So clearly something in my socket setup in Python needs to be setup in the same way in Elixir, but I can't seem to find the correct options in the gen_udp docs. How can I open a socket in Elixir for broadcast that will work the same as my udpsend.py routine in Python?

I am happy to accept an Erlang answer too.

As explained here , with UDP, you don't "open" a connection to an address/port, you simply send data to an address/port. In Erlang this is done using :gen_udp.send/4 which accepts a socket, address, port, and data.

If I start python udplisten.py in one shell and run the following from another:

iex(1)> {:ok, socket} = :gen_udp.open(0, [broadcast: true])
{:ok, #Port<0.1338>}
iex(2)> :gen_udp.send(socket, '255.255.255.255', 8477, "hello!")
:ok

I get this printed in the first shell:

('hello!', ('127.0.0.1', 54182))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM