Reputation: 893
I extended the websocket
echo server example (here) such that it is embedded into a Tkinter application. The server will be started when the "Start" button is pressed. Now I would like to stop the server when pressing the "Stop" button. However, close()
does not work.
server.py
:
try:
import Tkinter as Tk
from Tkinter import ttk
except ModuleNotFoundError:
import tkinter as Tk
from tkinter import ttk
import asyncio
import websockets
class TkEcho():
def __init__(self):
asyncio.get_event_loop().run_until_complete(self.main())
async def main(self):
'''
Add Buttons
'''
root = Tk.Tk()
Tk.Button(root, text='Start', command=lambda: self.start("localhost", 8765)).grid()
Tk.Button(root, text='Stop', command=self.stop).grid()
await self.run_tk(root)
async def run_tk(self, root, interval=0.05):
'''
Add Tk to asyncio
'''
try:
while True:
root.update()
await asyncio.sleep(interval)
except Tk.TclError as e:
if "application has been destroyed" not in e.args[0]:
raise
async def echo(self, websocket, path):
'''
Receives string and sends it back to sender
'''
string = await websocket.recv()
print(f"recv < {string}")
await websocket.send(string)
print(f"send > {string}")
def start(self, host, port):
'''
Starts websocket
'''
start_server = websockets.serve(self.echo, host, port)
asyncio.ensure_future(start_server)
def stop(self):
'''
Stops websocket
'''
None
if __name__ == "__main__":
t = TkEcho()
client.py
:
import asyncio
import websockets
async def send_recv():
uri = "ws://localhost:8765"
async with websockets.connect(uri) as websocket:
string = input("string to send? ")
await websocket.send(string)
print(f"send> {string}")
string = await websocket.recv()
print(f"recv< {string}")
asyncio.get_event_loop().run_until_complete(send_recv())
Solution:
replace TkEcho.__init__
with:
def __init__(self):
loop = asyncio.get_event_loop()
loop.create_task(self.main())
loop.run_forever()
And implement TkEcho.stop
as follows:
def stop(self):
'''
Stops websocket
'''
asyncio.get_event_loop().stop()
Upvotes: 0
Views: 5669
Reputation: 154836
To stop the program, you can simply stop the event loop:
def stop(self):
# terminate the loop
asyncio.get_event_loop().stop()
For this to work, you will need to use run_forever()
instead of run_until_complete()
to run the event loop:
def __init__(self):
loop = asyncio.get_event_loop()
loop.create_task(self.main())
loop.run_forever() # wait for loop.stop() to terminate us
Upvotes: 2