zoukankan      html  css  js  c++  java
  • 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>
  • 相关阅读:
    [Usaco2013 DEC] Vacation Planning
    [Usaco2015 DEC] Counting Haybales
    [ZJOI 2008] 泡泡堂BNB
    [USACO17FEB]Why Did the Cow Cross the Road II
    [Usaco2018 Feb] New Barns
    [HNOI 2006] 鬼谷子的钱袋
    [Usaco2017 Feb]Why Did the Cow Cross the RoadII
    初涉数论分块
    「在更」初涉历史最值线段树
    初涉DSU on tree
  • 原文地址:https://www.cnblogs.com/taoge188/p/10662144.html
Copyright © 2011-2022 走看看