"正在使用的地址"尝试从Erlang / Elixir进行UPD广播时出错

时间:2018-02-06 11:52:24

标签: tcp erlang elixir

为了让节点在我的局域网上找到主节点,我让主节点广播一条消息(带有它的IP地址)。它使用Python,没问题,但是使用Elixir我得到一个"地址在使用错误"当试图打开广播套接字时。这里有一些有效的Python代码:

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)

所以udpsend.py只是在端口8477上广播一个时间字符串,而udplisten.py会打印它所获得的任何内容。没有端口"地址在使用"运行此代码时出现冲突,无论先启动哪两个程序。

现在,如果我运行udplisten.py,然后尝试在Elixir中打开UDP套接字:

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}

我得到:错误元组:eaddrinuse。

请注意,如果udplisten.py没有运行,我不会这样做:

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

但是现在我的udplisten.py不起作用了:

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

很明显,我在Python中的套接字设置中的某些东西需要在Elixir中以相同的方式设置,但我似乎无法在gen_udp文档中找到正确的选项。如何在Elixir中打开一个套接字进行广播,它与Python中的udpsend.py例程一样?

我也很高兴接受Erlang的回答。

1 个答案:

答案 0 :(得分:2)

正如here所述,使用UDP,您不会打开&#34;连接到地址/端口,只需将数据发送到地址/端口即可。在Erlang中,这是使用:gen_udp.send/4来完成的,它接受套接字,地址,端口和数据。

如果我在一个shell中启动python udplisten.py并从另一个shell运行以下命令:

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

我在第一个shell中打印出来:

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