websocket

长轮询

在网页,我们经常扫码登录,结合之前的学习的知识点,来思考下,前端是如何知道用户在手机上扫码登录了呢?

长轮询:

客户端不断的向服务器发送请求

缺点:

1. 开销大 2. 浪费资源 3. 消耗流量

websocket介绍

长轮询消耗太多资源,其中主要原因是客户端和服务端并没有一直连接在一起,如果能够让客户端和服务器一直保持连接呢?

正经介绍

WebSocket 协议是基于 TCP 的一种新的 HTML5 网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并被RFC7936所补充规范

简单说

客户端和服务器一直连接在一起

websocket 服务端编程

第一步:导入

from tornado.websocket import WebSocketHandler

第二步:基类

class BaseWebsocketHandler(WebSocketHandler,SessionMixin):
    def get_current_user(self):
        current_user = self.session.get('user_ID')
        if current_user:
            return current_user
        return None

第三步:跳转 Handler

class IndexHandler(BaseHandler):
    @authenticated
    def get(self):
        self.render('08websocket.html')

第四步: websocket的Handler

class MessageHandler(BaseWebsocketHandler):
    '''
    建立连接
    收发数据
    断开连接
    '''
    users = set()
    #当我们的服务器想主动发送消息给浏览器的时候,调用write_message
    def open(self,*args,**kwargs):
        '''建立连接完成的代码逻辑'''
        MessageHandler.users.add(self)
        #服务器要告诉每一个客户端有人上线
        for i in self.users:
            # i.write_message('%s 上线了'%self.request.remote_ip)
            i.write_message('%s %s上线了'%(self.current_user,datetime.now()))

    def on_message(self, message):
        '''收发数据的代码逻辑'''
        print(message)
        for i in self.users:
            i.write_message('%s -%s 说:%s'%(self.current_user,datetime.now(),message))

    def on_close(self):
        '''断开连接的代码逻辑'''
        MessageHandler.users.remove(self)
        #服务器要告诉每一个客户端有人下线
        for i in self.users:
            # i.write_message('%s 下线了'%self.request.remote_ip)
            i.write_message('%s %s下线了'%(self.current_user,datetime.now()))

展示结果如下:

07-websocket.py代码如下:

import sys

import time
import tornado.web
import tornado.ioloop
import tornado.httpserver
import tornado.options
from tornado.web import RequestHandler,authenticated
from tornado.options import define,options
from pycket.session import SessionMixin
from tornado.websocket import WebSocketHandler
import util.ui_modules
import util.ui_methods
# import time
from datetime import datetime
from data.connect import session
from data.user_modules import UserDetails, User

define('port',default=8080,help='run server',type=int)

class BaseHandler(RequestHandler,SessionMixin):
    '''声明websocket基类'''
    def get_current_user(self):
        current_user = self.session.get('user_ID')
        if current_user:
            return current_user
        return None



class BaseWebsocketHandler(WebSocketHandler,SessionMixin):
    def get_current_user(self):
        current_user = self.session.get('user_ID')
        if current_user:
            return current_user
        return None


class IndexHandler(BaseHandler):
    @authenticated
    def get(self):
        self.render('08websocket.html')

class LoginHandler(BaseHandler):
    def get(self):
        next_name = self.get_argument('next','')
        self.render('in_out.html',nextname=next_name)

    def post(self):
        '''验证逻辑'''
        user = self.get_argument('name',None)
        password = self.get_argument('password',None)
        next_name = self.get_argument('next','')
        # print(next_name)
        # username = session.query(User).filter(User.username == user).first()
        username = User.get_name(user)
        # print(username)
        if username and  password == username.password:
            #如果判断用户可以登录,我们设置这样一个加密的cookie进去
            # self.set_secure_cookie('user_ID',user)
            self.session.set('user_ID',user)
            self.redirect(next_name)
        else:
            self.write('登录失败')


class MessageHandler(BaseWebsocketHandler):
    '''
    建立连接
    收发数据
    断开连接
    '''
    users = set()
    #当我们的服务器想主动发送消息给浏览器的时候,调用write_message
    def open(self,*args,**kwargs):
        '''建立连接完成的代码逻辑'''
        MessageHandler.users.add(self)
        #服务器要告诉每一个客户端有人上线
        for i in self.users:
            # i.write_message('%s 上线了'%self.request.remote_ip)
            i.write_message('%s %s上线了'%(self.current_user,datetime.now()))

    def on_message(self, message):
        '''收发数据的代码逻辑'''
        print(message)
        for i in self.users:
            i.write_message('%s -%s 说:%s'%(self.current_user,datetime.now(),message))

    def on_close(self):
        '''断开连接的代码逻辑'''
        MessageHandler.users.remove(self)
        #服务器要告诉每一个客户端有人下线
        for i in self.users:
            # i.write_message('%s 下线了'%self.request.remote_ip)
            i.write_message('%s %s下线了'%(self.current_user,datetime.now()))


application = tornado.web.Application(
    handlers=[
        (r'/index',IndexHandler),
        (r'/login',LoginHandler),
        (r'/websocket',MessageHandler),

    ],
    debug=True,
    template_path = 'templates',
    static_path='static',
    # autoescape = None, #全局取消转义
    ui_methods=util.ui_methods,
    ui_modules=util.ui_modules,
    cookie_secret ='qwe123', #cookie加盐
    login_url = '/login',
    pycket = {
        'engine':'redis',
        'storage':{
            'host':'localhost',
            'port':6379,
            'db_sessions':5,
            'max_connections':2**10,
        },
        'cookies':{
            'expires_days':7
        }
    }
)
if __name__ == '__main__':
    tornado.options.parse_command_line()
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.current().start()

webscoket 客户端编程

服务器已经解决,那么在客户端该怎么做呢?

WebSocket

WebSocket 是 HTML5 的标准之一,因此主流浏览器的 web 客户端编程语言 Javascript 已经支持 WebSocket 的客户端编程

初始化 WebSocket 对象

var socket = new WebSocket(url ):

处理函数

WebSocket.onopen : 此事件发生在 WebSocket 链接建立时

WebSocket.onmessage : 此事件发生在收到了来自服务器的消息时

WebSocket.onclose : 此事件发生在与服务器的链接关闭时

WebSocket.onerror : 此事件发生在通信过程中有任何错误时

主动操作函数

WebSocket.send(data) :向服务器发送消息

WebSocket.close() :主动关闭现有链接

08websocket.html代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title> WebSocket </title>
     <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.css" rel="stylesheet">
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        .box{
            width: 800px;
            margin-left: auto;
            margin-right: auto;
            margin-top: 25px;
        }
        #text{
            width: 685px;
            height: 130px;
            border: 1px solid skyblue;
            border-radius: 10px;
            font-size: 20px;
            text-indent: 1em;
            resize:none;
            outline: none;
        }
        #text::placeholder{
            color: skyblue;
        }
        .btn{
            width: 100px;
            margin: -27px 0 0px 8px;
        }
        #messages{
            padding-left: 10px;
            font-size: 25px;
        }
        #messages li{
            list-style: none;
            color: #000;
            line-height: 30px;
            font-size: 18px;

        }
    </style>
</head>
<body>
    <div class="box">
        <div>
            <textarea id="text" placeholder="请输入您的内容"></textarea>
            <a href="javascript:WebSocketSend();" class="btn btn-primary">发送</a>
        </div>
        <ul id="messages">
        </ul>
    </div>


    <script src="{{ static_url('js/jquery-2.2.0.min.js') }}"></script>


    <script type="text/javascript">

        var mes = document.getElementById('messages');
        if("WebSocket" in window){
            mes.innerHTML = "发送WebSocket请求成功!";
            var ws = new WebSocket("ws://127.0.0.1:8080/websocket");
            ws.onopen = function () {
            alert('连接已打开请聊天')
            };
            ws.onmessage = function (goudan) {

                var received_msg = goudan.data;

                var aLi = $("<li>"+received_msg+"</li>");
                // $(mes).append($(aLi)) //  方法一
    //            $(aLi).appendTo(mes); //  方法二
                $(mes).prepend($(aLi)) //  方法一

            };
            ws.onclose = function () {
                mes.innerHTML = mes.innerHTML + "<br>连接已经关闭...";
            };
        } else {
            mes.innerHTML = "发送WebSocket请求失败!"
        }

        function WebSocketSend() {
            ws.send($("#text").val());
            $("#text").val("");
        }
    </script>

</body>
</html>
原文地址:https://www.cnblogs.com/taoge188/p/10662144.html