Christopher Pisz
Christopher Pisz

Reputation: 4010

Twisted UDP - Why can't I send without listening?

How do I send without calling Reactor.ListenUDP? If I try, then I get an exception in the protocol class that the transport is NULL. It seems it doesn't get set up in the base class until you call the reactor.ListenUDP. Surely, you have the ability to send without listening for incoming messages. After all, a server might not even want to receive at all.

----main.py------

import wx
from twisted.internet import wxreactor
from main_window import MainWindow


def main():
    app = wx.App(False)
    frame = MainWindow(None, 'UDP Demo')

    from twisted.internet import reactor
    reactor.registerWxApp(app)
    reactor.run()


if __name__ == "__main__":
    wxreactor.install()
    main()

---main_window.py---

# SNIP - Nothing really relevant. Just creates the classes below and hooks up buttons to call their methods

---plugin.py----

from enum import Enum
from twisted.internet.error import CannotListenError

from udp_protocol import UDPProtocol


class PluginBase(object):
    """
    This is just a dummy class to match what is in Falco
    """

    def __init__(self, app_dist, *args, **kwargs):
        pass


class Plugin(PluginBase):
    class State(Enum):
        """
        Represents the states that the plugin can be in
        """
        CLOSED = 0                     # Initial state
        LISTENING = 1                  # After open() is called
        RECV_CALLBACK_REGISTERED = 2   # After listen() is called

    def __init__(self, app_dist, *args, **kwargs):
        super(Plugin, self).__init__(app_dist, *args, **kwargs)
        self.state = self.State.CLOSED
        self.port = None
        self.listener = None
        self.listen_callback = None
        self.protocol = UDPProtocol(self.on_data_received)

    def listen(self, port, isBroadcast, callback, errback=None):
        if self.state != self.State.CLOSED:
            raise RuntimeError("UDP Plugin already in an opened state")
        self.port = port

        # Start listening
        try:
            from twisted.internet import reactor
            self.listener = reactor.listenUDP(self.port, self.protocol)
            self.state = self.State.LISTENING
            callback()
        except CannotListenError as err:
            error_json = {"error": err[2].strerror}
            if errback is not None:
                errback(error_json)

    def stop_listening(self):
        if self.listener is not None:
            self.listener.stopListening()
            self.listener = None

        self.listen_callback = None
        self.port = None
        self.state = self.State.CLOSED

    def send(self, addr, port, data):
        # While it seems like one could send without listening for incoming messages,
        # twisted's implementation doesn't seem to work that way?
        # The transport in the protocol object only gets created when we call reactor.listenUDP,
        # as far as I can tell
        if self.state == self.State.CLOSED:
            raise RuntimeError(
                "UDP Plugin must be in an open state before attempting to send")

        self.protocol.send(addr, port, data)

    # SNIP recv

----udp_protocol.py---

from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor


class MyProtocol(DatagramProtocol):

    def datagramReceived(self, data, (host, port)):
        print "received %r from %s:%d" % (data, host, port)
        self.transport.write(data, (host, port))

    def send(self, addr, port, data):
        self.transport.write(data, (addr, port))

Upvotes: 0

Views: 154

Answers (1)

Jean-Paul Calderone
Jean-Paul Calderone

Reputation: 48335

Surely, you have the ability to send without listening for incoming messages.

As it turns out, no. However, nothing compels you to do anything with any incoming messages that arrive.

Upvotes: 1

Related Questions