tornado 是一個用Python語言寫成的Web服務器兼Web應用框架,以下記錄如何用 tornado framework 撰寫 websocket Echo Server & Client。
安裝 tornado
在 debian 安裝 python library
wget https://bootstrap.pypa.io/get-pip.py
sudo python get-pip.py
sudo pip install tornado
在 mac 安裝 tornado
sudo port install py27-tornado
Echo Server
# -*- coding: utf-8 -*-
import datetime
import sys
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
class WSHandler(tornado.websocket.WebSocketHandler):
clients = []
def check_origin(self, origin):
return True
def open(self):
print "New client connected"
#self.write_message("You are connected")
WSHandler.clients.append(self)
def on_message(self, message):
self.write_message(message)
def on_close(self):
print "Client disconnected"
WSHandler.clients.remove(self)
@classmethod
def write_to_clients(cls):
print "Writing to clients"
for client in cls.clients:
client.write_message("Hi there!")
application = tornado.web.Application([
(r"/", WSHandler),
])
if __name__ == "__main__":
try:
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(9000)
main_loop = tornado.ioloop.IOLoop.instance()
# Schedule event (5 seconds from now)
#main_loop.add_timeout(datetime.timedelta(seconds=5), WSHandler.write_to_clients)
# background update every x seconds
# 固定每 5 秒鐘就呼叫一次 WSHandler.write_to_clients 廣播訊息
task = tornado.ioloop.PeriodicCallback(
WSHandler.write_to_clients,
5 * 1000)
task.start()
# Start main loop
#main_loop.start()
main_loop.make_current()
except KeyboardInterrupt:
#print("KeyboardInterrupt")
sys.exit()
EchoServer in aother Thread
將 Server 放在另一個 Thread 啟動,保留 main thread 用在其他的用途上。
# -*- coding: utf-8 -*-
import datetime
import sys
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
import os
from threading import Thread
class WSHandler(tornado.websocket.WebSocketHandler):
clients = []
def check_origin(self, origin):
return True
def open(self):
print "New client connected"
#self.write_message("You are connected")
WSHandler.clients.append(self)
def on_message(self, message):
self.write_message(message)
def on_close(self):
print "Client disconnected"
WSHandler.clients.remove(self)
@classmethod
def write_to_clients(cls):
print "Writing to clients"
for client in cls.clients:
client.write_message("Hi there!")
class WebThread(Thread):
def __init__(self):
Thread.__init__(self, name='WebThread')
def run(self):
curdir = os.path.dirname(os.path.realpath(__file__))
application = tornado.web.Application([
(r"/", WSHandler),
])
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(9000)
main_loop = tornado.ioloop.IOLoop.instance()
# Schedule event (5 seconds from now)
#main_loop.add_timeout(datetime.timedelta(seconds=5), WSHandler.write_to_clients)
# background update every x seconds
# 固定每 5 秒鐘就呼叫一次 WSHandler.write_to_clients 廣播訊息
task = tornado.ioloop.PeriodicCallback(
WSHandler.write_to_clients,
5 * 1000)
task.start()
main_loop.start()
if __name__ == "__main__":
try:
webThread = WebThread()
webThread.daemon = True
webThread.start()
while True:
pass
except KeyboardInterrupt:
#print("KeyboardInterrupt")
sys.exit()
EchoClient.html
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
var socket = new WebSocket('ws://127.0.0.1:9000/');
socket.onopen = function(event){
socket.send('Hi');
}
socket.onmessage = function(event){
console.log(event.data);
};
$(window).unload(function(event){
socket.close();
});
});
</script>
Echo Client with tornado framework
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
from tornado.ioloop import IOLoop, PeriodicCallback
from tornado import gen
from tornado.websocket import websocket_connect
class Client(object):
def __init__(self, url, timeout):
self.url = url
self.timeout = timeout
self.ioloop = IOLoop.instance()
self.ws = None
self.connect()
# 每 20 秒發送一次 ping
PeriodicCallback(self.keep_alive, 20000, io_loop=self.ioloop).start()
self.ioloop.start()
@gen.coroutine
def connect(self):
print "trying to connect"
try:
self.ws = yield websocket_connect(self.url)
except Exception, e:
print "connection error"
else:
print "connected"
self.run()
@gen.coroutine
def run(self):
while True:
msg = yield self.ws.read_message()
if msg is None:
print "connection closed"
self.ws = None
break
else:
print msg
def keep_alive(self):
if self.ws is None:
self.connect()
else:
self.ws.write_message("ping")
if __name__ == "__main__":
try:
client = Client("ws://localhost:9000", 5)
except KeyboardInterrupt:
#print("KeyboardInterrupt")
sys.exit()
References
SIMPLE WEB SOCKET CLIENT IMPLEMENTATION USING TORNADO FRAMEWORK.
沒有留言:
張貼留言