标签 Tornado 下的文章

这次使用Python来进行Websocket通信,使用Tornado自带的Websocket库,与游览器自带的api。

目录结构

.
├── static
│   └── index.html
└── websockettest.py

Python

#coding=utf-8
import tornado.web
import tornado.websocket
import tornado.httpserver
import tornado.ioloop

client_list = [] #连接用户列表

class WebSocketHandler(tornado.websocket.WebSocketHandler):
        def open(self): #连接进入
                #print(dir(self)) #康康对象有什么
                client_list.append(self)
                pass
        def on_message(self,message): #消息事件
                print(message)
                for client in client_list: #将消息发送到所有在线的连接
                        client.write_message(message)
        def on_close(self): #关闭事件
                client_list.remove(self)
                pass
        def check_origin(self,origin): #允许跨域访问
                print(origin)
                return True
class IndexPageHandler(tornado.web.RequestHandler):
        def get(self):
                self.render('index.html')

class Application(tornado.web.Application):
        def __init__(self):
                handlers = [(r'/',IndexPageHandler),(r'/websocket',WebSocketHandler)]
                settings = {'template_path':'static'} #设置模板文件目录
                tornado.web.Application.__init__(self,handlers,**settings)

if __name__ == '__main__':
        app = Application()
        tornado.httpserver.HTTPServer(app).listen(80)
        tornado.ioloop.IOLoop.instance().start()

Html & JavaSscript

<title>WebSockets Test</title>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script type="text/javascript">
var ws = new WebSocket("ws://ip/websocket"); #你可以在本地保存网页测试(跨域请求)
//ws.onopen = function(){
//      ws.send('hello!');
//}
ws.onmessage = function(msg){
        $('.message').append("<p>" + msg.data + "</p>");
}
ws.onclose = function(){
        $('.message').append("<p>Connection closed</p>");
}
function sendmsg(){
        var msg = $("#msg").val();
        ws.send(msg);
}
</script>
<div class='message'></div>
<textarea id="msg"></textarea>
<button type="but" onclick="sendmsg()">Send</button>

其他

上次Nodejs的Express-ws网页测试不成功的原因是Socket.io的问题,Socket.io会向socket.io/?EIO=&transport=websocket请求连 接,只有服务端一起使用Socket.io才能正常连接,使用游览器自带访问正常连接(更新:之前不了解Socket.io的工作模式写的不对的话)。

Cookie

由于HTTP协议是无状态的(一旦数据交换完毕就断开连接),很难知道客户端的身份,再次连接也不知道,在这种情况下,Cookie诞生了,它是服务器留在客户端的一小段信息,用于区分客户身份,游览器每次在请求时,都会在头文件上带上这个Cookie。
演示(Web.py):

#coding=utf-8
import web
urls = ('/', 'hello') #路由
class hello:
    def GET(self):
        web.setcookie('test_cookie','hello')
        return 'Hello,world!'

if __name__ == "__main__":
    app = web.application(urls, globals())
    app.run()

Session(会话)

会话是Cookie后另一种解决方式,与Cookie最大的不同是会话存储在服务器,尽管会话依赖于Cookie(会话需要存储会话ID),但客户端除了会话ID也无法篡改其他,极大的提高了安全性。
1.

//由于Tornado没有Session模块,所以找了一些轮子,需要Redis支持
https://github.com/zs1621/tornado-redis-session
https://github.com/cole/tornado-sessions

2.目前用的

pip install pycket
pip install redis

例子:

import tornado.ioloop
import tornado.web
from pycket.session import SessionMixin

class MainHandler(tornado.web.RequestHandler,SessionMixin):
    def get(self):
        test = self.session.get('test_session')
        if test:
            self.write(test)
        else:
            self.session.set('test_session','hello')
            self.write("Hello, world")
if __name__ == "__main__":
    settings = {}
    settings['pycket'] = {}
    settings['pycket']['cookies'] = {}
    settings['pycket']['storage'] = {}
    settings['cookie_secret'] = 'f8lNNzhHTVSOyKab3MKv6A=='
    settings['pycket']['engine'] = 'redis' #数据库类型
    settings['pycket']['storage']['host'] = 'localhost' #host
    settings['pycket']['storage']['port'] = 6379 #端口
    settings['pycket']['storage']['db_sessions'] = 10 #用于会话的数据集
    settings['pycket']['storage']['db_notifications'] = 16 #用于通知的数据集
    settings['pycket']['storage']['max_connections'] = 2**64 #最大连接数
    settings['pycket']['cookies']['expires_days'] = 1 #会话过期时间
    settings['pycket']['cookies']['max_age'] = 86400 #兼容设置,同上
    print(settings)
    app = tornado.web.Application([(r'/', MainHandler),],**settings)
    app.listen(8080)
    tornado.ioloop.IOLoop.current().start()