我正在 raspbian 上使用 Elixir/Erlang 包来尝试构建一个简单的 UDP 发送/接收应用程序。作为信息,我正在使用本教程。
当我尝试将 UDP 数据包发送到接口指定的广播 IP 地址上的网络时eth0
,我收到一条“权限被拒绝”消息。
难道真的不允许从linux向网络广播UDP消息吗?如果是这样,如何授予特定包广播消息的权限?我已经使用 IP 地址 127.0.0.1 对其进行了测试localhost
,没有收到任何错误。
答案1
要使用 BSD 套接字 API 发送广播,您必须声明您的目的地是广播地址。这是通过系统调用完成的setsockopt(2)
。
这是一个例子,自愿不使用二郎因为:
- 我不知道二郎
- 该问题与 erlang 无关,而是与 BSD 套接字 API 相关。
我将用 IPv4 来说明环回地址。本地主机不仅仅是 127.0.0.1,而且目前是 127.0.0.1/8,因此是 127.0.0.0/8 网络块的一部分。这意味着(至少在目前的 Linux 上)这确实支持广播语义,如下所示:
$ ip route get 127.255.255.255
broadcast 127.255.255.255 dev lo table local src 127.0.0.1 uid 1000
cache <local,brd>
所以用方便的方式复制socat
命令是调试与应用程序通信的好工具:
$ echo test | socat udp4-datagram:127.255.255.255:5555 -
2021/07/04 08:40:06 socat[327412] E sendto(5, 0x55976a7a1000, 5, 0, AF=2 127.255.255.255:5555, 16): Permission denied
这需要声明目的地是广播:
$ echo test | socat udp4-datagram:127.255.255.255:5555,broadcast -
$ echo $?
0
$ echo test | strace -e trace=socket,setsockopt,sendto -- socat udp4-datagram:127.255.255.255:5555,broadcast -
socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) = 5
setsockopt(5, SOL_SOCKET, SO_BROADCAST, [1], 4) = 0
sendto(5, "test\n", 5, 0, {sa_family=AF_INET, sin_port=htons(5555), sin_addr=inet_addr("127.255.255.255")}, 16) = 5
+++ exited with 0 +++
二郎setsockopt(2)
其参考文献中有内网模块文档参考:socket_setopt()
.
socket_setopt() = gen_sctp:option() | gen_tcp:option() | gen_udp:option()
setopts(Socket, Options) -> ok | {error, posix()} Types Socket = socket() Options = [socket_setopt()]
为套接字设置一个或多个选项。
{broadcast, Boolean} (UDP sockets)
启用/禁用发送广播的权限。
您必须弄清楚如何将其添加到您的二郎代码。