• socketserver模块使用 & websocket


    socketserver:

    socketserver可用于实现并发通信。

    socketserver 模块简化了编写网络服务程序的任务;同时 SocketServer 模块也是 Python标准库中很多服务器框架的基础。
    socketserver 模块可以简化网络服务器的编写。Python把网络服务抽象成两个主要的类,一个是 Server 类,用于处理连接相关的网络操作,另外一个则是 RequestHandler 类,用于处理数据相关的操作;并且提供了两个Mixin类,用于扩展 Server,实现多进程或多线程。

    Server 类:
    它包含了种五种server类,BaseServer(不直接对外服务)。TCPServer使用TCP协议,UDPServer使用UDP协议,还有两个不常使用的,
    即UnixStreamServer和UnixDatagramServer,这两个类仅仅在unix环境下有用(AF_unix)。

    RequestHandler类:
    所有requestHandler都继承BaseRequestHandler基类。

    注: 全双工管道通信:既可以 收,也可以 发

    单工、半双工和全双工的区别: https://blog.csdn.net/starstar1992/article/details/53032409

    socketserver 的使用方法:

    import socketserver
    
    """
    socketserver: 基于多线程实现的并发通信
    sockerserver 使用方法(固定套路):
    1. 定义功能类
        class MyServer(socketserver.BaseRequestHandler):  
            def handler(self):  
                pass
    
    2. server = socketserver.threadingTCPServer(("127.0.0.1",8800),MyServer) 
    
    3. server.server_forerver()  
    """
    
    class MyServer(socketserver.BaseRequestHandler):  # 必须要继承 socketserver.BaseRequestHandler 这个类
        
        def handler(self):  # 必须要有 handler() 这个方法
            """
            handler() 方法里面要放并发的业务逻辑
            该方法下的 self.request 也是固定写法,是一个套接字对象,即相当于 以前 socket 时的 conn
            """
            # 写自己的业务逻辑
            pass
    
    
    # 通过 socketserver 引一个要 并发的类
    server = socketserver.ThreadingTCPServer(("127.0.0.1",8800),MyServer)   # 第一个参数:IP和端口,第二个参数:要实例化的 功能类;threadingTCPServer 这个类是通过 多线程 帮我们实现的并发;用的是 TCP 协议
    # server = socketserver.ForkingTCPServer(("127.0.0.1",8800),MyServer)  # 多进程 TCP 通信
    server.server_forerver()

    websocket:

    websocket 其实就是 web socket,它也是一种协议
    
    http 的问题:
        1. http 是一个协议
            - 数据格式
            - 一次请求和响应之后断开连接(无状态、短连接)
        2. 服务端不可以向客户端主动推送消息(因为不知道客户端的IP端口)
        3. 服务端只能做出响应
        4. 为了伪造服务端向客户端主动推送消息的效果,我们使用:轮询和长轮询
    
    websocket 是一种新的协议: 1. 连接时需要握手;2.发送数据进行加密;3.连接之后不断开;  websocket 解决了 服务端能够真正向客户端推送消息;缺点:兼容性 
        - 数据格式:
            - 连接请求: http协议
            - 收发请求: websocket协议
        - 不断开连接
        
    基于 flask的websocket示例:
    # 安装:
    pip install gevent-websocket

    支持 websocket 的框架:
      所有框架都支持,但是,
      flask : gevent-websocket
      django:channel
      tornado 框架自带 websocket

    应用场景:实时响应

    基于 flask 和 websocket 实现一个在线投票功能:

    app.py

    from flask import Flask,render_template,request
    import json
    
    # 使用 websocket 时 需要导入下面的两个模块
    from geventwebsocket.handler import WebSocketHandler
    from gevent.pywsgi import WSGIServer
    
    
    # 发送 websocket 请求得通过 js 来实现
    
    app = Flask(__name__)
    
    USERS = {
        '1':{'name':'钢弹','count':0},
        '2':{'name':'铁锤','count':0},
        '3':{'name':'贝贝','count':100},
    }
    
    
    # http://127.0.0.1:5000/index  # 浏览器在渲染 index.html 时,在执行 var ws = new WebSocket('ws://192.168.13.253:5000/message') 这句js代码时,客户端就会和服务端建立一个 websocket 的连接
    @app.route('/index')
    def index():
        return render_template('index.html',users=USERS)
    
    # http://127.0.0.1:5000/message
    WEBSOCKET_LIST = []  # 用于保存所有的 websocket 连接;可理解为所有的客户端
    
    @app.route('/message')
    def message():
        ws = request.environ.get('wsgi.websocket')  # 如果不是 websocket 协议的请求,request.environ.get('wsgi.websocket') 的值是 None;如果是 websocket 请求, ws 将是一个 websocket 对象
        if not ws:
            print('http')
            return '您使用的是Http协议'
        WEBSOCKET_LIST.append(ws)  # 把当前的 ws 连接添加到 WEBSOCKET_LIST 中
        while True:
            cid = ws.receive()  # 接收投票的 cid; ws.receive() :接收客户端发过来的 websocket协议的 数据
            if not cid: # 如果客户端关闭连接 ws.receive() 接收到的将会是 None
                WEBSOCKET_LIST.remove(ws)
                ws.close()  # 后台的 ws 也关闭
                break
                
            old = USERS[cid]['count']
            new = old + 1
            USERS[cid]['count'] = new
            
            for client in WEBSOCKET_LIST:
                client.send(json.dumps({'cid':cid,'count':new}))  # 给前端返回一个字典
    
    # 服务端通过 websocket 协议就可以向客户端主动推送消息;这是由于 客户端与服务端的连接没有断开; 需要事先在客户端的浏览器上 new 一个 WebSocket 的对象 (WebSocket 支持H5等,但低版本的浏览器不支持)
    
    if __name__ == '__main__':
        http_server = WSGIServer(('0.0.0.0', 5000), app, handler_class=WebSocketHandler)  # 如果是 http 协议的请求,就交给 app 去处理;如果是 websocket 协议的请求,就交给 WebSocketHandler 去处理。 # app 的 werkzeug 只能处理 http 请求
        http_server.serve_forever()

    index.html

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
    </head>
    <body>
        <h1>丑男投票系统</h1>
        <ul>
            {% for k,v in users.items() %}
                <li onclick="vote({{k}})" id="id_{{k}}">{{v.name}}<span>{{v.count}}</span></li>
            {% endfor %}
        </ul>
    
        <script src="{{ url_for('static',filename='jquery-3.3.1.min.js')}}"></script>
        <script>
            var ws = new WebSocket('ws://192.168.13.253:5000/message')  // 实例化一个WebSocket 对象: 用于向 192.168.13.253:5000/message 这个url 发送 websocket 协议的请求;该连接不会断开 
            // 前端通过 ws.send("你好")  来发送 websocket协议的数据
            
            ws.onmessage = function (event) {  // 服务端返回 ws 数据的时候, ws.onmessage() 自动触发
                /* 服务器端向客户端发送数据时,自动执行 */
                // {'cid':cid,'count':new}
                var response = JSON.parse(event.data);  // event.data 就是 服务端返回回来的数据
                $('#id_'+response.cid).find('span').text(response.count);
    
            };
    
            function vote(cid) {
                ws.send(cid)   // 发送 websocket 数据
            }
        </script>
    </body>
    </html>
  • 相关阅读:
    EXTJS4.2——0.简介
    什么是JDBC?
    Applet和普通的Java应用程序有什么区别?
    final关键字、finally代码块和finalize()方法有什么区别?
    throw和throws有什么区别
    Java中的两种异常类型是什么?他们有什么区别?
    Java堆的结构是什么样子的?什么是堆中的永久代(Perm Gen space)?
    flash插件
    算法复杂度分析中的符号(大Θ符号、大Ο符号...)
    Enumeration接口和Iterator接口的区别有哪些?
  • 原文地址:https://www.cnblogs.com/neozheng/p/10159273.html
Copyright © 2020-2023  润新知