python的WebSocket编程详解,案例群聊系统实现

1.websocket相关

1.1为什么要用websocket

如果有需求要实现服务端向客户端主动推送消息时(比如聊天室,群聊室)有哪几种方案

  • 轮训:让浏览器每隔两秒发送一次请求,缺点:有延时,请求太多网站压力大;
  • 长轮训:客户端向服务端发送请求,服务端最多夯20秒,一旦有新的数据就立即返回断开请求
  • websocket:客户端和服务端创建链接请求不断开,实现双向通道。(推荐)

WebSocket 是一种在 Web 应用程序中实现双向通信的协议。相较于传统的 HTTP 请求-响应模式,WebSocket 提供了全双工的通信方式,使得服务器和客户端之间能够实时地进行双向数据传输。

下面是一些 WebSocket 的应用场景:

  1. 实时聊天:WebSocket 可以用于实时的聊天应用,例如在线客服系统、实时消息推送等。通过 WebSocket 协议,可以实现高效、低延迟的消息传递,提供更好的用户体验。
  2. 多人协作:WebSocket 可以用于多人协作应用,例如实时的协同编辑器、白板工具等。多个用户可以同时编辑共享的文档或画布,实时地看到其他用户的修改。
  3. 实时数据展示:WebSocket 可以用于实时监控和数据展示应用,例如股票行情图、实时天气预报等。通过 WebSocket,可以实时地获取最新的数据,并将其实时展示给用户。
  4. 游戏开发:WebSocket 在游戏开发中也发挥着重要作用。它可以用于实时的游戏对战、多人游戏中的实时交互等。通过 WebSocket,可以实现游戏中玩家之间的实时通信和数据传输。
  5. 远程监控:WebSocket 可以用于远程监控和控制应用,例如远程桌面、远程设备管理等。通过 WebSocket,可以实现实时的屏幕共享、远程操作等功能。

我基于websocket+Django写了一个简单的群聊系统。有感兴趣的同学可以参考我下面提供的源码进行学习,有不懂的,欢迎各位打扰!

下载链接:https://pan.baidu.com/s/1wLhkcRV-3awFz9XMxfWegQ?pwd=yyds
提取码:yyds

1.2websocket介绍

websocket 就是web版的socket

原来的Web中:

  • http协议,无状态,短链接

    • 需要客户端主动链接服务器
    • 客户端再向服务端发送消息,服务端接收消息在响应返回数据
    • 客户端收到数据
    • 断开请求链接
  • https协议,是http+对数据进行加密

我们在开发过程中想要保留一些状态信息,基于Cookie来做

现在web支持:

  • http/https协议,一次请求一次响应
  • websocket协议,创建持久的连接请求不断开,基于这个连接可以进行收发数据,用于【服务端向客户端主动推送消息】
    • web聊天室
    • 实时的图表,柱状图,饼图,投票。
1.3websocket原理
  • http协议

    • 连接
    • 数据传输
    • 断开链接
  • websocket协议,是建立在http协议之上

    • 连接,客户端发起

    • 握手(验证),客户端发送一个消息,服务端收到消息做一些特殊处理并返回。服务器端支持websocket协议。

      • 客户端向服务端发送

        GET /chatsocket HTTP/1.1
        Host:127.0.0.1:8002
        Connection:Upgrade
        Pragma:no-cache
        Cache-Control:no-cache
        Upgrade:websocket
        Origin:http://localhost:63342
        Sec-WebSocket-Version:13
        Sec-WebSocket-Key:mnwFxiOlctXFN/DeMt1Amg==
        Sec-WebSocket-Extensions:permessage-deflate;client_max_window_bits
        ...
        ...
        
        
      • 服务器接收(重要)*

      Sec-WebSocket-Key:mnwFxiOlctXFN/DeMt1Amg==与 magic string 进行拼接
      magic string = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
      v1 = "mnwFxiOlctXFN/DeMt1Amg==" + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
      v2 = hmacl(v1)加密1
      v3 = base64(v2)加密2
      
      • 如果服务端匹配成功返回客户端

        HTTP/1.1 101 Switching protocols
        Upgrade:websocket
        Connection:Upgrade
        Sec-WebSocket-Accept:密文(v3)
        
    • 收到数据(加密)

      dfanfsdfmkdsgg;fnfsnfonaoiasdono;fsofnoskfaj
      
      • 先获取两个字节8位。例如10001010

      • 再获取第二个字节的后7位。例如0001010 ——》payload lens

        • =127 ,两个字节8位, 其他字节(4字节masking key + 用户数据)
        • =126 ,两个字节, 其他字节(4字节masking key + 用户数据)
        • <=125 ,两个字节8位, 其他字节(4字节masking key + 用户数据)
      • 获取masking Key 然后对数据进行解密

        var DECODED = " ";
        for(var i = 0;i < DECODED.length;i++){
        DECODED[i]= ENCODED[i]^ MASK[i%4];
        }
        
    • 断开连接

      1.4Django + WebSocket
  • 安装websocket 第三方包

    Django默认不支持websocket,需要安装组件

     pip3 install channels
    
  • 配置

    • 注册channels

      INSTALLED_APPS = [
          'django.contrib.admin',
          'django.contrib.auth',
          'django.contrib.contenttypes',
          'django.contrib.sessions',
          'django.contrib.messages',
          'django.contrib.staticfiles',
          'channels'
      ]
      
      
      • 在setting.py中添加asgi_application

        ASGI_APPLICATION = "websocket.asgi.application"
        
      • 在asgi.py文件中修改

        import os
        from django.core.asgi import get_asgi_application
        from channels.routing import ProtocolTypeRouter,URLRouter
        from . import routing
        os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'websocketp.settings')
        
        # application = get_asgi_application()
        application = ProtocolTypeRouter({
            "http": get_asgi_application(),
            "websocket": URLRouter(routing.websocket_urlpatterns),
        })
        
      • 在setting同级目录下创建websocket_urls.py

        from django.urls import re_path
        from app01 import websocket_views
        
        websocket_urlpatterns = [
            re_path()
        ]
        
      • 在app01目录下创建websocket_views.py,编写处理websocket的业务逻辑

        from channels.generic.websocket import WebsocketConsumer
        from channels.exceptions import StopConsumer
        
        class ChatConsumer(WebsocketConsumer):
            def websocket_connect(self, message):
                # 有客户端来向服务端发送websocket连接的请求时,自动触发
                # 服务端允许和客户端创建连接
                self.accept()
            def websocket_receive(self, message):
                # 浏览器基于websocket向服务端发送数据,自动触发接收客户端消息
                print(message)
                self.send("你好呀你好")
                self.close()  #表示服务器端主动断开连接
            def websocket_disconnect(self, message):
                # 客户端与服务器断开连接时,自动触发
                print("断开连接")
                raise StopConsumer()
        
    • 在Django中:

      • WSGI:在以前的学习Django,都是用WSGI
      • ASGI:WSGI+异步编程+websocket
1.5聊天室
  • 访问地址看到聊天室的页面,http请求

  • 让客户端主动向服务端发起websocket连接,服务端接收连接后通过(握手)。

    • 客户端,websocket。

      socket = new WebSocket("ws://localhost:8000/room/123/");     		
      
    • 服务端 握手并连接成功

      from channels.generic.websocket import WebsocketConsumer
      from channels.exceptions import StopConsumer
      
      class ChatConsumer(WebsocketConsumer):
          def websocket_connect(self, message):
              print("有人来连接了....")
              # 有客户端来向服务端发送websocket连接的请求时,自动触发
              # 服务端允许和客户端创建连接(握手)
              self.accept()
      
    • 收发消息

    • 收发消息(客户端的向服务端发消息)

      • 客户端

            
      • 服务端

        from channels.generic.websocket import WebsocketConsumer
        from channels.exceptions import StopConsumer
        
        class ChatConsumer(WebsocketConsumer):
            def websocket_connect(self, message):
                print("有人来连接了....")
                # 有客户端来向服务端发送websocket连接的请求时,自动触发
                # 服务端允许和客户端创建连接(握手)
                self.accept()
            def websocket_receive(self, message):
                # 浏览器基于websocket向服务端发送数据,自动触发接收客户端消息
                print("接收到消息了",message)
        
  • 收发消息(服务端给客户端发消息)

    • 服务端

      from channels.generic.websocket import WebsocketConsumer
      from channels.exceptions import StopConsumer
      
      class ChatConsumer(WebsocketConsumer):
          def websocket_connect(self, message):
              print("有人来连接了....")
              # 有客户端来向服务端发送websocket连接的请求时,自动触发
              # 服务端允许和客户端创建连接(握手)
              self.accept()
              # 服务端给客户端发消息
              self.send("来了呀客官")         ### 服务端给客户端发消息
      
    • 客户端

      
                          
                          

你可能感兴趣的:(Python,python,websocket,开发语言)