我在Ubuntu 14.04服务器上工作,该服务器在不同的子网上有多个接口。我正在尝试编写一个扭曲的(13.2.0)应用程序,它只在一个接口上侦听广播,而忽略其他接口。
我可以用这个代码接收广播。
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
import IN, socket, struct
class BroadcastListener(DatagramProtocol):
def startProtocol(self):
self.transport.getHandle().setsockopt(socket.SOL_SOCKET,
socket.SO_BROADCAST, True)
def datagramReceived(self, datagram, address):
print "Received datagram from %s" % (address[0])
#reactor.listenUDP(65001, BroadcastListener(), interface='192.168.1.1')
reactor.listenUDP(3200, BroadcastListener())
reactor.run()
我正在用socat从192.168.1.x子网上的另一台机器发送测试UDP广播。
echo Hi |socat - UDP-DATAGRAM:192.168.1.255:3200,broadcast
但是,这将在服务器上的任何接口上接收广播。我以为它会指定reactor.listenUDP()中的接口,就像我进行评论调用一样。
如果我使用包含接口的reactor.listenUDP()调用,我将不再接收广播。我仍然收到socat发送的单播UDP。
echo Hi |socat - UDP-DATAGRAM:192.168.1.1:3200
当指定接口时,我可以看到套接字绑定到接口。
$ netstat -an |grep udp |grep 3200
udp 0 0 10.10.0.1:3200 0.0.0.0:*
但广播正在被取消。我用tcpdump确认广播正在到达服务器。
在twistedpython中设置UDP侦听器接口的正确方法是什么?
我假设您在这里使用Linux。bind()
似乎不起作用,因为它丢弃了未寻址到接口的数据包,而对于广播数据包来说,接口就是所有数据包。相反,请尝试套接字选项SO_BINDTODEVICE
,它可能不在您的Python socket
模块中,但在我的Linux系统上,可能在您的Linux系统中具有值25
(请检查/usr/include/asm-generic/socket.h
)。它需要一个接口名称而不是IP地址,所以它应该看起来像这样:
self.transport.getHandle().setsockopt(socket.SOL_SOCKET, 25, "eth0")