简体   繁体   中英

Receiving broadcast UDP on a specific interface with Twisted Python

I am working on an Ubuntu 14.04 server with multiple interfaces on different subnets. I am trying to write a twisted(13.2.0) application that listens for broadcasts on one interface only, ignoring the other interfaces.

I am able to receive broadcasts with this code.

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()

I am sending test UDP broadcasts from another machine on the 192.168.1.x subnet with socat.

echo Hi |socat -  UDP-DATAGRAM:192.168.1.255:3200,broadcast

However, this will receive broadcasts on any interface on the server. I thought it would be specificying the interface in reactor.listenUDP(), as I did the commented call.

If I use the reactor.listenUDP() call that includes the interface, I no longer receive broadcast. I still receive unicasted UDP sent with socat.

echo Hi |socat -  UDP-DATAGRAM:192.168.1.1:3200

I can see when specifying the interface that the socket is bound to the interface.

$ netstat -an |grep udp |grep 3200
udp        0      0 10.10.0.1:3200          0.0.0.0:*

But the broadcasts are being dropped. I confirmed with tcpdump the broadcasts are arriving to the server.

What is the correct way to set a UDP listener's interface in twisted python?

I'm assuming you're on Linux here. It seems that bind() won't work because it drops packets not addressed to the interface, which for broadcast packets is all of them. Instead, try the socket option SO_BINDTODEVICE , which may not be in your Python socket module, but has the value 25 on my Linux system and probably on yours (check /usr/include/asm-generic/socket.h ). It takes an interface name rather than an IP address, so it should look something like this:

self.transport.getHandle().setsockopt(socket.SOL_SOCKET, 25, "eth0")

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