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.
:gen_udp.open
is the local port address. An UDP message has a sender and a destination and both are specified by an IP address and a port. You tried to bind your socket to the local port number 8477, which was a port that the Python script already was using; by sending "0" along , you tell the networking stack "give me a random port number". - cdegroot