mirror of https://github.com/kivy/kivy.git
fix threading issue on reactor stop, and add server and client example to documentation
This commit is contained in:
parent
609b03bb37
commit
d57f58d5c3
|
@ -13,39 +13,136 @@ passed on the the threadedselect reactors interleave function, these
|
|||
are the arguments one would usually pass to twisted's reactor.startRunning
|
||||
|
||||
.. warning::
|
||||
Unlike the default twisted reactor, the installed reactor will not handle
|
||||
any signals unnless you set the 'installSignalHandlers' keyword argument
|
||||
to 1 explicitly. This is done to allow kivy to handle teh signals as
|
||||
usual, unless you specifically want the twisted reactor to handle the
|
||||
signals (e.g. SIGINT).
|
||||
Unlike the default twisted reactor, the installed reactor will not handle
|
||||
any signals unnless you set the 'installSignalHandlers' keyword argument
|
||||
to 1 explicitly. This is done to allow kivy to handle teh signals as
|
||||
usual, unless you specifically want the twisted reactor to handle the
|
||||
signals (e.g. SIGINT).
|
||||
|
||||
Here is a brief example kivy application that has a twisted server running
|
||||
inside it::
|
||||
'''
|
||||
Test app using the Echo server from the twisted documentation
|
||||
you can find simpleserv.py and simpleclient.py here:
|
||||
inside it. It based mostly on simple Echo example from the twisted docs,
|
||||
which you can find here:
|
||||
http://twistedmatrix.com/documents/current/core/examples/simpleserv.py
|
||||
http://twistedmatrix.com/documents/current/core/examples/simpleclient.py
|
||||
'''
|
||||
|
||||
|
||||
echo_server_app.py::
|
||||
|
||||
#install_twisted_rector must be called before importing and using the reactor
|
||||
from kivy.support import install_twisted_reactor
|
||||
install_twisted_reactor()
|
||||
|
||||
|
||||
from twisted.internet import reactor
|
||||
from twisted.internet import protocol
|
||||
|
||||
class EchoProtocol(protocol.Protocol):
|
||||
def dataReceived(self, data):
|
||||
response = self.factory.app.handle_message(data)
|
||||
self.transport.write(response)
|
||||
|
||||
class EchoFactory(protocol.Factory):
|
||||
protocol = EchoProtocol
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
|
||||
|
||||
from kivy.app import App
|
||||
from kivy.uix.button import Button
|
||||
from kivy.uix.label import Label
|
||||
|
||||
class TwistedTestApp(App):
|
||||
class TwistedServerApp(App):
|
||||
def build(self):
|
||||
self.setup_twisted_server()
|
||||
return Button(text="Hello" )
|
||||
self.label = Label(text="server started\n")
|
||||
reactor.listenTCP(8000, EchoFactory(self))
|
||||
return self.label
|
||||
|
||||
def setup_twisted_server(self):
|
||||
from kivy.support import install_twisted_reactor
|
||||
install_twisted_reactor()
|
||||
def handle_message(self, msg):
|
||||
response = "echo: <%s>" % msg
|
||||
if msg == "ping": response = "pong"
|
||||
if msg == "plop": response = "kivy rocks"
|
||||
|
||||
self.label.text = "received: %s\n" % msg
|
||||
self.label.text += "responded: %s\n" % response
|
||||
return response
|
||||
|
||||
from twisted.internet import reactor, protocol
|
||||
from simpleserv import Echo
|
||||
factory = protocol.ServerFactory()
|
||||
factory.protocol = Echo
|
||||
reactor.listenTCP(8000, factory)
|
||||
|
||||
if __name__ == '__main__':
|
||||
setup_twisted_server()
|
||||
TwistedTestApp().run()
|
||||
TwistedServerApp().run()
|
||||
|
||||
|
||||
echo_client_app.py::
|
||||
|
||||
#install_twisted_rector must be called before importing the reactor
|
||||
from kivy.support import install_twisted_reactor
|
||||
install_twisted_reactor()
|
||||
|
||||
|
||||
#A simple Client that send messages to the echo server
|
||||
from twisted.internet import reactor, protocol
|
||||
|
||||
class EchoClient(protocol.Protocol):
|
||||
def connectionMade(self):
|
||||
self.factory.app.print_message("connected successfully")
|
||||
self.factory.app.echo_transport = self.transport
|
||||
|
||||
def dataReceived(self, data):
|
||||
self.factory.app.print_message(data)
|
||||
|
||||
class EchoFactory(protocol.ClientFactory):
|
||||
protocol = EchoClient
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
|
||||
def clientConnectionLost(self, conn, reason):
|
||||
self.app.print_message("connection lost")
|
||||
|
||||
def clientConnectionFailed(self, conn, reason):
|
||||
self.app.print_message("connection failed")
|
||||
|
||||
|
||||
from kivy.app import App
|
||||
from kivy.uix.label import Label
|
||||
from kivy.uix.textinput import TextInput
|
||||
from kivy.uix.boxlayout import BoxLayout
|
||||
|
||||
#A simple kivy App, with a textbox to enter messages, and
|
||||
#a large label to display all the messages received from
|
||||
#the server
|
||||
class TwistedClientApp(App):
|
||||
echo_transport = None
|
||||
|
||||
def build(self):
|
||||
root = self.setup_gui()
|
||||
self.connect_to_server()
|
||||
return root
|
||||
|
||||
def setup_gui(self):
|
||||
self.textbox = TextInput(size_hint_y=.1, multiline=False)
|
||||
self.textbox.bind(on_text_validate=self.send_message)
|
||||
self.label = Label(text='connecting...\n')
|
||||
self.layout = BoxLayout(orientation='vertical')
|
||||
self.layout.add_widget(self.label)
|
||||
self.layout.add_widget(self.textbox)
|
||||
return self.layout
|
||||
|
||||
def connect_to_server(self):
|
||||
reactor.connectTCP('localhost', 8000, EchoFactory(self))
|
||||
|
||||
def send_message(self, *args):
|
||||
msg = self.textbox.text
|
||||
if msg and self.echo_transport:
|
||||
self.echo_transport.write(str(self.textbox.text))
|
||||
self.textbox.text = ""
|
||||
|
||||
def print_message(self, msg):
|
||||
self.label.text += msg + "\n"
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TwistedClientApp().run()
|
||||
|
||||
|
||||
Run echo_server_app.py first, and then launch echo_client_app.py. The server
|
||||
will, reply with simple echo messages to anything the client app sends, when
|
||||
you hit enter after typing something in teh textbox.
|
||||
|
||||
|
|
|
@ -65,25 +65,26 @@ def install_twisted_reactor(*args, **kwargs):
|
|||
#now we can import twisted reactor as usual
|
||||
from twisted.internet import reactor
|
||||
from kivy.base import EventLoop
|
||||
from kivy.core.window import Window
|
||||
from kivy.clock import Clock
|
||||
from kivy.logger import Logger
|
||||
import thread, threading
|
||||
|
||||
#hook up rector to our reactor wake function
|
||||
def reactor_wake(twisted_loop_next):
|
||||
'''called whenever twisted needs to do work
|
||||
'''
|
||||
|
||||
def call_twisted(*args):
|
||||
Logger.trace("Entering Twisted event loop")
|
||||
twisted_loop_next()
|
||||
Clock.schedule_once(call_twisted, -1)
|
||||
twisted_loop_next()
|
||||
reactor.interleave(reactor_wake, *args, **kwargs)
|
||||
|
||||
#make sure twisted reactor is shutdown if eventloop exists
|
||||
def reactor_stop(*args):
|
||||
'''will shutdown the twisted reactor main loop'''
|
||||
from twisted.internet import reactor
|
||||
Logger.debug("Shutting down twisted reactor")
|
||||
reactor._mainLoopShutdown()
|
||||
'''will shutdown the twisted reactor main loop
|
||||
'''
|
||||
if not reactor._stopped:
|
||||
Logger.debug("Shutting down twisted reactor" )
|
||||
reactor.stop()
|
||||
if threading.current_thread() != reactor.workerThread:
|
||||
thread.exit()
|
||||
EventLoop.add_stop_callback(reactor_stop)
|
||||
|
||||
|
|
Loading…
Reference in New Issue