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

这篇具有很好参考价值的文章主要介绍了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()
      
    • 收发消息

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

      • 客户端

            <div>
                <input type="text" placeholder="请输入" id="txt">
                <input type="button" value="发送" onclick="sendMessage()">
            </div>
            <script>
                socket = new WebSocket("ws://localhost:8000/room/123/");
                function sendMessage(){
                    let tag = document.getElementById("txt");
        
                    socket.send(tag.value);
                }
        
            </script>
        
      • 服务端

        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("来了呀客官")         ### 服务端给客户端发消息
      
    • 客户端

      <script>
              socket = new WebSocket("ws://localhost:8000/room/123/");
              socket.onmessage = function (event){
                  console.log(event.data)
              }
      
      • 回调函数 onmessage :当websocket接收到服务端发来的消息时,自动会触发这个函数

        socket.onmessage = function (event){}

      • 回调函数onopen : 当创建好连接之后会自动触发,服务端执行self.accept()之后

        socket.onopen = function (event){}

      • 服务端主动断开连接时,这个方法会被自动触发

      • socket.onclose = function (event){}

      • <script>
                socket = new WebSocket("ws://localhost:8000/room/123/");
                // 当创建好连接之后会自动触发,服务端执行self.accept()之后
                socket.onopen = function (event){
                    let tag = document.createElement("div");
                    tag.innerText = "[连接成功]";
                    document.getElementById("message").appendChild(tag);
                }
                // 当websocket接收到服务端发来的消息时,自动会触发这个函数
                socket.onmessage = function (event){
                    let tag = document.createElement("div");
                    tag.innerText = event.data;
                    document.getElementById("message").appendChild(tag);
                }
                // 服务端主动断开连接时,这个方法会被自动触发
                socket.onclose = function (event){
                    let tag = document.createElement("div");
                    tag.innerText = "[断开连接]";
                    document.getElementById("message").appendChild(tag);
                }
                function sendMessage(){
                    let tag = document.getElementById("txt");
        
                    socket.send(tag.value);
                }
                function closeConn(){
                    socket.close();// 向服务端发送断开连接的请求
                }
            </script>
        
1.6 群聊1
  • 群聊的简单实现

    from channels.generic.websocket import WebsocketConsumer
    from channels.exceptions import StopConsumer
    
    CONN_LIST = []
    class ChatConsumer(WebsocketConsumer):
        def websocket_connect(self, message):
            print("有人来连接了....")
            # 有客户端来向服务端发送websocket连接的请求时,自动触发
            # 服务端允许和客户端创建连接(握手)
            self.accept()
            CONN_LIST.append(self)
            # 服务端给客户端发消息
            # self.send("来了呀客官")
        def websocket_receive(self, message):
            # 浏览器基于websocket向服务端发送数据,自动触发接收客户端消息
            print("接收到消息了",message)
            text = message['text']
            print("收到消息", text)
            # if text == '关闭':
            #     # 想要服务端断开连接, 会给客户端发送断开连接的消息
            #     self.close()
            #     return
    
            res = '{}SB'.format(text)
            for conn in CONN_LIST:
                conn.send(res)
            # self.send(res)
            # self.close()  #表示服务器端主动断开连接
    
        # 不管是客户端还是服务端要主动断开时都会执行这个方法
        def websocket_disconnect(self, message):
            # 客户端与服务器断开连接时,自动触发
            print("断开连接")
            CONN_LIST.remove(self)
            raise StopConsumer() # 服务端允许客户端断开连接
    
1.7 群聊2

基于channels中提供的channels layers 来实现,需要做以下配置

  • setting中配置。

    方法一:将多个人的连接存储在当前服务器下的内存中

    # 相当于我们自定义的 consumers.py下定义的CONN_LIST = [],意思是 将多个人的连接存储在当前服务器下的内存中   也可以将多个人的连接放在使用redis
    CHANNEL_LAYERS = {
        "default": {
            "BACKEND": "channels.layers.InMemoryChannelLayer"
        }
    }
    
    

    方法二:也可以将多个人的连接放在使用redis

    CHANNEL_LAYERS = {
        "default": {
            "BACKEND": "channels_redis.core.RedisChannelLayer",
            "CONFIG": {
                "hosts": ['ip', 'port']
            }
        }
    }
    
  • 实现方法:

    from channels.generic.websocket import WebsocketConsumer
    from channels.exceptions import StopConsumer
    from asgiref.sync import async_to_sync
    
    class ChatConsumer(WebsocketConsumer):
        def websocket_connect(self, message):
            # 接收这个客户端的连接
            self.accept()
            # 将这个客户端的连接对象加入某个地方  (内存 or redis)
            # 群号  和别名
            # 获取群号
            group = self.scope['url_route']['kwargs'].get("group")
            async_to_sync(self.channel_layer.group_add)(group, self.channel_name)
    
        def websocket_receive(self, message):
            # 通知组内的所有客户端,执行 xx_oo方法 ,在此方法中自己可以去定义任意的功能
            group = self.scope['url_route']['kwargs'].get("group")
            async_to_sync(self.channel_layer.group_send)(group, {"type": "xx.oo", "message": message})
    
        def xx_oo(self, event):
            text = event['message']['text']
            self.send(text)
    
        # 不管是客户端还是服务端要主动断开时都会执行这个方法
        def websocket_disconnect(self, message):
            # 客户端与服务器断开连接时,自动触发
            group = self.scope['url_route']['kwargs'].get("group")
            async_to_sync(self.channel_layer.group_discard)(group, self.channel_name)
            raise StopConsumer()  # 服务端允许客户端断开连接
    
1.8 总结
  • websocket是什么?协议
  • django中实现websocket,要用到channels组件
    • 单独连接的(一对一)的收发数据
    • 多对多的(比如说群聊)实现 基于Channels_layers

2.websocket编程的代码实例

在 Python 中,有许多库可以用于实现 WebSocket 功能,其中比较常用的是 websockets 库。以下是使用 websockets 库在 Python 中实现一个简单的 WebSocket 服务器和客户端的示例代码:

WebSocket 服务器端代码:

import asyncio
import websockets

async def handle_websocket(websocket, path):
    # 处理 WebSocket 连接
    while True:
        message = await websocket.recv()
        print(f"Received message: {message}")

        # 这里可以根据收到的消息进行相应的处理逻辑

        response = f"Server received: {message}"
        await websocket.send(response)
        print(f"Sent response: {response}")

start_server = websockets.serve(handle_websocket, "localhost", 8765)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

WebSocket 客户端代码:

import asyncio
import websockets

async def connect_websocket():
    async with websockets.connect("ws://localhost:8765") as websocket:
        while True:
            message = input("Enter a message to send: ")
            await websocket.send(message)
            print(f"Sent message: {message}")

            response = await websocket.recv()
            print(f"Received response: {response}")

asyncio.get_event_loop().run_until_complete(connect_websocket())

这个示例实现了一个简单的回显功能,当客户端发送消息给服务器时,服务器会将收到的消息原样返回给客户端。

你可以先运行 WebSocket 服务器端代码,在命令行中执行 python server.py,然后再运行 WebSocket 客户端代码,执行 python client.py。在客户端输入消息后,服务器会收到该消息并返回给客户端,客户端再将接收到的响应消息打印出来。文章来源地址https://www.toymoban.com/news/detail-785352.html

到了这里,关于python的WebSocket编程详解,案例群聊系统实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 10.NIO 网络编程应用实例-群聊系统

    需求:进一步理解 NIO 非阻塞网络编程机制,实现多人群聊 编写一个 NIO 群聊系统,实现客户端与客户端的通信需求(非阻塞) 服务器端:可以监测用户上线,离线,并实现消息转发功能 客户端:通过 channel 可以无阻塞发送消息给其它所有客户端用户,同时可以接受其它客户端用

    2024年02月15日
    浏览(32)
  • Python中的WebSocket编程

    WebSocket是一种网络通信协议,它在单个TCP连接上提供全双工的通信信道。在本篇文章中,我们将探讨如何在Python中使用WebSocket实现实时通信。 1. 什么是WebSocket? WebSocket协议是在2008年由Web应用程序设计师和开发人员创建的,目的是为了在Web浏览器和服务器之间提供更高效、更

    2024年01月20日
    浏览(30)
  • python网络编程之websocket

    我们知道一般我们的请求都是http请求,由客户端发起,然后待服务端返回数据之后,这一个请求就结束了。但是,有些情况下,服务端需要主动给客户端发消息(比如推送一些消息),服务端与客户端需要进行双向交流,此时,http就显得有些无能为力了。所以就有了全双工

    2024年02月10日
    浏览(33)
  • 由浅入深介绍 Python Websocket 编程

    1.1 websocket 协议简介 Websocket协议是对http的改进,可以实现client 与 server之间的双向通信; websocket连接一旦建立就始终保持,直到client或server 中断连接,弥补了http无法保持长连接的不足,方便了客户端应用与服务器之间实时通信。 适用场景 html页面实时更新, 客户端的html页面

    2024年02月03日
    浏览(34)
  • Python编程实现百度AI开放平台的接口对接方法,详解和实践指南

    Python编程实现百度AI开放平台的接口对接方法,详解和实践指南 引言 百度AI开放平台提供了丰富的人工智能接口,包括语音识别、图像识别、自然语言处理等功能。本文将通过Python编程,详解如何对接百度AI开放平台的接口,并提供实际代码示例。 准备工作 在开始之前,我们

    2024年02月13日
    浏览(33)
  • JavaEE 初阶篇-深入了解 UDP 通信与 TCP 通信(综合案例:实现 TCP 通信群聊)

    🔥博客主页: 【 小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录         1.0 UDP 通信         1.1 DatagramSocket 类         1.2 DatagramPacket 类         1.3 实现 UDP 通信(一发一收)         1.3.1 客户端的开发         1.3.2 服务端的开发         1.4 实

    2024年04月26日
    浏览(32)
  • 第61讲:Python编程案例之角谷猜想

    日本的角谷提出了一个猜想:对于任意的自然数,反复进行如下的运算,总可以得到运算结果1: 如果自然数为奇数,那么乘以3然后加1。 如果自然数为偶数,则除以2。 基于这两个运算策略,任何自然数经过反复运算,总可以得到结果1。 这个猜想到目前为止不认为是正确的

    2024年02月10日
    浏览(20)
  • Python快速编程入门 第2版 实训案例及课后编程题

    目录 第2章 第3章 第4章 第5章 第6章 第7章 第8章  第9章 第10章 第11章(代码过多不在此处进行书写,需要的可以自行下载) http://链接:https://pan.baidu.com/s/1bqg62id6zn8UF8gGiGYSGg?pwd=gnub 提取码:gnub 本文档仅供参考,更新了8/9/10章 2.4.1打印购物小票 蚂蚁森林是支付宝客户端发起“

    2024年02月03日
    浏览(21)
  • Python web实战之Django 的 WebSocket 支持详解

     :Python, Django, WebSocket, Web   如何使用 Django 实现 WebSocket 功能?本文将详细介绍 WebSocket 的概念、Django 的 WebSocket 支持以及如何利用它来创建动态、响应式的 Web 应用。   1.1 什么是 WebSocket? 在 Web 开发中,当我们需要实现实时交互、即时通信或实时更新数据的功能时

    2024年02月12日
    浏览(31)
  • python GUI编程--实现计算器和图书管理系统注册和登录的可视化操作

    1.简易计算器:编写程序,实现两个数的“加减乘除”,界面如图所示  2.利用tkinter设计一个登录界面,并实现各个命令按钮的功能: 3.利用tkinter设计一个下面的界面, 该界面的功能是:当单击“insert point”按钮时,第一个文本框的内容复制一份显示在第二个文本框内,当单

    2024年02月10日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包