websocket 单点通信,广播通信

news2024/11/26 23:20:22

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

参考:

HTML5 WebSocket | 菜鸟教程

由浅入深介绍 Python Websocket 编程-CSDN博客

应用场景:

        html单点通信

        消息群发

        聊天室功能

一,单点通信

      1,server.py

import asyncio
import websockets
from datetime import datetime

async def handler(websocket):
    data = await websocket.recv()
    reply = f"收到数据:{data}  time: {datetime.now()}"
    print(reply)
    await websocket.send(reply)
    print("Send reply")


async def main():
    async with websockets.serve(handler, "localhost", 9999):
        await asyncio.Future()  # run forever

if __name__ == "__main__":
    asyncio.run(main())


        2,python 客户端 client.py

import asyncio
import websockets
import time

async def ws_client(url):
    for i in range(1, 40):
        async with websockets.connect(url) as websocket:
            await websocket.send("Hello, I'm client 1")
            response = await websocket.recv()
        print(response)
        time.sleep(3)


if __name__ == "__main__":
    asyncio.run(ws_client('ws://127.0.0.1:9999'))

        3,html客户端client.html

<!DOCTYPE HTML>
<html>

<head>
    <meta charset="utf-8">
    <title>websocket demo</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/css/bootstrap.min.css">
    <script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js">		</script>
    <script src="https://cdn.staticfile.org/popper.js/1.15.0/umd/popper.min.js"></script>
    <script src="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
    <script type="text/javascript">

            async function wsClient(url) {
                for (let i = 1; i <= 40; i++) {
                    const websocket = new WebSocket(url);

                    // Wait for the WebSocket connection to open
                    await new Promise((resolve, reject) => {
                        websocket.addEventListener('open', () => {
                            resolve();
                        });
                        websocket.addEventListener('error', reject);
                    });

                    // Send a message to the server
                    websocket.send("Hello, I'm client html");

                    // Wait for a response from the server
                    const response = await new Promise((resolve) => {
                        websocket.addEventListener('message', (event) => {
                            resolve(event.data);
                        });
                    });

                    // Print the response
                    console.log(response);

                    // Wait for 3 seconds before sending the next message
                    await new Promise(resolve => setTimeout(resolve, 1000));

                    // Close the WebSocket connection before the next iteration
                    websocket.close();
                }
            }                
 
        // Call the function with the desired WebSocket URL
        wsClient('ws://127.0.0.1:9999');
    </script>

</head>

<body>

</body>

</html>

        4,启动  :

        python server.py

        python client.py       

         

        打开client.html

二,广播消息

        1,server.py

import asyncio
import websockets
from datetime import datetime,time

# 维护一个连接的客户端字典,key为remote_address
connected_clients = {}

# 处理连接事件
async def connection_handler(websocket, path):
    remote_address = websocket.remote_address
    print(f"新连接建立 from {remote_address}")
    connected_clients[remote_address] = websocket  # 使用remote_address作为key添加到字典中
    print(f"当前连接数:{len(connected_clients)}")
    print(f"连接地址:{list(connected_clients.keys())}")
    try:
        while True:
            await message_handler(websocket)
    except websockets.exceptions.ConnectionClosedOK:
        print(f"连接已正常关闭 from {remote_address}")
        print(f"当前连接地址:{list(connected_clients.keys())}")
    finally:
        del connected_clients[remote_address]  # 连接关闭时从字典中移除

# 处理接收到的消息,并广播出去
async def message_handler(websocket):
    data = await websocket.recv()
    reply = f"收到数据:{data}  time: {datetime.now().time()}"
    print(reply)
    

    # 广播消息给所有连接的客户端
    for client_websocket in connected_clients.values():
        if client_websocket != websocket:  # 避免给自己发送消息
            try:
                await client_websocket.send(reply)
            except websockets.exceptions.ConnectionClosedError:
                # 如果某个客户端连接已经关闭,由于字典的key-value特性,无需显式移除
                print(f"一个连接已关闭,自动从字典中移除")
    print("Broadcast reply sent")

async def main():
    async with websockets.serve(connection_handler, "localhost", 9999):
        await asyncio.Future()  # run forever

if __name__ == "__main__":
    asyncio.run(main())

        2,client.py

import asyncio
import websockets

async def ws_client(url):
    async with websockets.connect(url) as websocket:
        # 发送初始消息
        await websocket.send("Hello, I'm logging.")
        
        # 持续接收消息的循环
        while True:
            try:
                response = await websocket.recv()
                print(f"Received: {response}")
                # 可以根据需要处理接收到的消息,比如判断是否需要发送新的消息等
            except websockets.exceptions.ConnectionClosedError:
                print("Connection closed by server.")
                break  # 连接关闭时跳出循环
            except Exception as e:
                print(f"An error occurred: {e}")
                # 根据实际情况决定是否需要重连或进行其他操作
                
            # 可以在这里添加延时以控制发送或接收频率,但需谨慎使用以免阻塞事件循环
            # await asyncio.sleep(1)  # 示例:每秒接收一次消息


if __name__ == "__main__":
    asyncio.run(ws_client('ws://127.0.0.1:9999'))

        3,html

<!DOCTYPE HTML>
<html>

<head>
    <meta charset="utf-8">
    <title>websocket demo</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/css/bootstrap.min.css">
    <script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js">		</script>
    <script src="https://cdn.staticfile.org/popper.js/1.15.0/umd/popper.min.js"></script>
    <script src="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
    <script type="text/javascript">
        var ws; // 在更宽的作用域定义WebSocket实例

        function WebSocketTest() {
            if ("WebSocket" in window) {
                ws = new WebSocket("ws://127.0.0.1:9999/handler"); // 打开WebSocket连接

                ws.onopen = function () {
                    ws.send("html login");
                    console.log("发送消息(html login)");
                };

                ws.onclose = function () {
                    console.log("连接已关闭...");
                };
            } else {
                alert("您的浏览器不支持 WebSocket!");
            }
        }

        // 新增函数,用于发送消息
        function sendMessage() {
            if (ws && ws.readyState === WebSocket.OPEN) { // 确保WebSocket已连接且处于OPEN状态
                var msgInput = document.getElementById("msgInput"); // 假设有一个输入框用于输入消息
                var msg = msgInput.value || "默认消息内容";
                ws.send(msg);
                console.log("发送消息:" + msg);
                msgInput.value = ""; // 清空输入框
            } else {
                console.warn("WebSocket未连接或非OPEN状态,无法发送消息。");
            }
        }
    </script>
</head>

<body>
    <div class="col-md-6 m-5 p-2" id="div_ws">
        <a class="btn btn-primary" href="javascript:WebSocketTest()">登录WebSocket</a>
    </div>
    <div class="col-md-6 m-5 p-2" id="div_ws">
        <a class="btn btn-primary" onclick="sendMessage()" >发送消息</a>
    </div>


    <div class="input-group input-group-lg">
        <div class="input-group-prepend">
          <span class="input-group-text" id="inputGroup-sizing-lg">消息</span>
        </div>
        <input type="text"   id="msgInput"  class="form-control" aria-label="Sizing example input" aria-describedby="inputGroup-sizing-lg"  placeholder="请输入消息内容..." >
      </div>

</body>

</html>

      4,终端启动服务端 

        python server.py

        5,打开多个终端启动多个客户端

                python client.py   

        6,打开html页面,点击登录WebSocket按钮

        7,输入框输入消息,点击发送消息

三,html 聊天室功能

        1,server.py 

        启动服务端 python server.py

    # reply = f"收到数据:{data}  time: {datetime.now().time()}" 修改响应数据

    reply = f"{datetime.now().time()} {websocket.remote_address} {data}"

      2,  client.html

<!DOCTYPE HTML>
<html>

<head>
    <meta charset="utf-8">
    <title>websocket demo</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/css/bootstrap.min.css">
    <script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js">		</script>
    <script src="https://cdn.staticfile.org/popper.js/1.15.0/umd/popper.min.js"></script>
    <script src="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
    <script type="text/javascript">
        var ws; // 在更宽的作用域定义WebSocket实例

        function WebSocketTest() {
            if ("WebSocket" in window) {
                ws = new WebSocket("ws://127.0.0.1:9999/handler"); // 打开WebSocket连接
                ws.onopen = function () {
                    ws.send("html login");
                    console.log("发送消息(html login)");
                };

                ws.onmessage = function (event) { // 添加消息接收处理器
                    var receivedMsg = document.getElementById("receivedMsg"); // 获取用于显示消息的元素
                    receivedMsg.innerHTML += "<br>" + event.data; // 将接收到的消息追加到元素中
                    console.log("接收到消息:" + event.data);
                };

                ws.onclose = function () {
                    console.log("连接已关闭...");
                };
            } else {
                alert("您的浏览器不支持 WebSocket!");
            }
        }

        // 新增函数,用于发送消息
        function sendMessage() {
            if (ws && ws.readyState === WebSocket.OPEN) { // 确保WebSocket已连接且处于OPEN状态
                var msgInput = document.getElementById("msgInput"); // 假设有一个输入框用于输入消息
                var msg = msgInput.value || "默认消息内容";
                ws.send(msg);
                console.log("发送消息:" + msg);
                msgInput.value = ""; // 清空输入框
            } else {
                console.warn("WebSocket未连接或非OPEN状态,无法发送消息。");
            }
        }
    </script>
</head>

<body>
    <div class="col-md-6 m-5 p-2" id="div_ws">
        <a class="btn btn-primary" href="javascript:WebSocketTest()">登录WebSocket</a>
    </div>
    <div class="col-md-6 m-5 p-2" id="div_ws">
        <a class="btn btn-primary" onclick="sendMessage()">发送消息</a>
    </div>
    <div class="input-group input-group-lg">
        <div class="input-group-prepend">
            <span class="input-group-text" id="inputGroup-sizing-lg">消息</span>
        </div>
        <input type="text" id="msgInput" class="form-control" aria-label="Sizing example input"
            aria-describedby="inputGroup-sizing-lg" placeholder="请输入消息内容...">
    </div>

    <div class="col-md-12 m-5 p-2" id="receivedMsg" style="height: 200px;overflow-y: scroll;">
        消息记录区:
    </div>
</body>

</html>

        3,打开3个client.html 客户端,并发送数据

       客户端1,

客户端2,

客户端3,

四,单人聊天功能分析

        1,把获取客户端字典做成api

        2,打开client.html 请求接口获取客户端字典,相当于获取在线好友列表

        3,发送消息,携带通信好友的客户端字典的key值,

        4,服务端从客户端字典查找目标连接,并发送消息

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1632036.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

信息系统管理

目录 一、信息系统管理范围 1、规划和组织 2、设计和实施 ①、信息系统架构 Ⅰ、集中式架构 Ⅱ、分布式架构 Ⅲ、SOA&#xff08;面向服务的系统架构&#xff09; 3、运维和服务 ①、运行管理和控制 ②、IT服务管理 ③、运行与监控 Ⅰ、运行监控 Ⅱ、安全监控 4、…

【题解】—— LeetCode一周小结17

【题解】—— 每日一道题目栏 上接&#xff1a;【题解】—— LeetCode一周小结16 22.组合总和 Ⅳ 题目链接&#xff1a;377. 组合总和 Ⅳ 给你一个由 不同 整数组成的数组 nums &#xff0c;和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数…

01.Kafka简介与基本概念介绍

1 Kafka 简介 Kafka 是最初由 Linkedin公司开发&#xff0c;是一个分布式、支持分区(partition)的、多副本(replica)的&#xff0c;基于 Zookeeper 协调的分布式消息系统&#xff0c;它的最大的特性就是可以实时的处理大量数据以满足各种需求场景&#xff1a;比如基于 hadoop 的…

SpringBoot 快速开始 Dubbo RPC

文章目录 SpringBoot 快速开始 Dubbo RPC下载 Nacos项目启动项目的创建创建主项目接口定义服务的创建Dubbo 服务提供者的创建服务的消费者创建 添加依赖给 Provider、Consumer 添加依赖 开始写代码定义接口在 Provider 中实现在 Consumer 里面使用创建启动类 注册中心配置启动 …

R-Tree: 原理及实现代码

文章目录 R-Tree: 原理及实现代码1. R-Tree 原理1.1 R-Tree 概述1.2 R-Tree 结构1.3 R-Tree 插入与查询 2. R-Tree 实现代码示例&#xff08;Python&#xff09;结语 R-Tree: 原理及实现代码 R-Tree 是一种用于管理多维空间数据的数据结构&#xff0c;常用于数据库系统和地理信…

党建3d互动虚拟现实网上展厅有何优势?

在数字化浪潮席卷全球的今天&#xff0c;企业如何迅速踏上虚拟世界的征程&#xff0c;开启元宇宙之旅?答案就是——3D虚拟云展。这一创新平台&#xff0c;华锐视点以虚拟现实技术和3D数字建模为基石提供3D云展搭建服务&#xff0c;助力企业轻松搭建起虚拟数字基础设施&#xf…

Rust Web开发实战:打造高效稳定的服务端应用

Rust Web开发实战&#xff1a;打造高效稳定的服务端应用 本书将带领您从零开始构建Web应用程序&#xff0c;无论是API、微服务还是单体应用&#xff0c;都将一一涵盖。您将学到如何优雅地对外开放API&#xff0c;如何连接数据库以安全存储数据&#xff0c;以及如何对应用程序进…

用结构体把驱动层和应用层分开

用正点原子代码的usmart分析&#xff0c;如下&#xff1a; usmart.h usmart_config.c 实例&#xff1a;把结构体与具体驱动绑定一起 /* 正点原子的usmart串口的封装 涉及文件&#xff1a;usmart.h usmart.c usmart_config.c 还有外面使用的文件&#xff08;应用层调用&#xff…

Rocketmq 5 分级存储 Tieredstore(RIP-57、RIP-65) 原理详解 源码解析

1. 背景 RocketMQ 5.x 的演进目标之一是云原生化&#xff0c;在云原生和 Serverless 的浪潮下&#xff0c;需要解决 RocketMQ 存储层存在两个瓶颈。 数据量膨胀过快&#xff0c;单体硬件无法支撑存储的低成本和速度无法兼得 众多云厂商也希望提供 Serverless 化的 RocketMQ …

【源码阅读】 Golang中的database/sql库源码探究

Note&#xff1a;文章待完结 文章目录 前言一、整体目录结构二、driver包1、驱动相关driver.Driver2、驱动连接&#xff1a;driver.Conn3、预处理结构&#xff1a;Stmt4、执行结果 driver.Result5、查询结果&#xff1a;driver.Rows6、driver.RowsAffected7、driver.Value8、Va…

IDEA主题美化【保姆级】

前言 一款好的 IDEA 主题虽然不能提高我们的开发效率&#xff0c;但一个舒适简单的主题可以使开发人员更舒适的开发&#xff0c;时常换一换主题可以带来不一样的体验&#xff0c;程序员的快乐就这么简单。话不多说&#xff0c;先上我自己认为好看的主题设置。 最终效果图: 原…

《我们为什么爱喝酒》酒精如何决定人类社会成败 - 三余书屋 3ysw.net

我们为什么爱喝酒&#xff1a;酒精如何决定人类社会成败 大家好&#xff0c;今天我们要解读的书是《我们为什么爱喝酒&#xff1f;》&#xff0c;副标题是“酒精如何决定人类社会成败”。你平时会喝酒吗&#xff1f;你如何看待“喝酒有害健康”这一观点&#xff1f;欢迎在评论…

stm32单片机开发三、DMA

DMA其实就是一种将ADC的数据寄存器、串口的数据寄存器等等一些数据放到sram中特定位置&#xff0c;方便CPU去读取 比如ADC转换&#xff0c;DMA直接转换的ADC的值放在内存中的特定位置&#xff0c;CPU可以直接去读取 uint16_t AD_Value[4]; //定义用于存放AD转换结果的全局…

如何让用户听话?

​福格教授&#xff08;斯坦福大学行为设计实验室创始人&#xff09;通过深入研究人类行为20年&#xff0c;2007年用自己的名子命名&#xff0c;提出了一个行为模型&#xff1a;福格行为模型。 模型表明&#xff1a;人的行为发生&#xff0c;要有做出行为的动机和完成行为的能…

在IDEA中使用.env文件导入系统配置的图文教程

JetBrains的IDEA是一款功能强大的集成开发环境&#xff0c;为开发人员提供了丰富的功能和工具。使用.env文件来管理配置信息在IDEA中非常简单。 旧版本默认支持&#xff0c;新版本idea需要安装插件才可以。 这里我们可以安装EnvFile插件&#xff0c;步骤如下&#xff1a; 在弹…

回归预测 | Matlab实现NGO-ESN北方苍鹰算法优化回声状态网络多输入单输出回归预测

回归预测 | Matlab实现NGO-ESN北方苍鹰算法优化回声状态网络多输入单输出回归预测 目录 回归预测 | Matlab实现NGO-ESN北方苍鹰算法优化回声状态网络多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现NGO-ESN北方苍鹰算法优化回声状态网络…

利用NetBIOS欺骗攻击盗取hash(2)

LLMNR和NetBIOS欺骗 原理探究 在使用传输控制协议 (TCP) 和互联网协议 (IP) 堆栈的网络&#xff08;包括当今大多数网络&#xff09;上&#xff0c;需要将资源名称转换为 IP 地址以连接到这些资源。因此&#xff0c;网络需要将“resource.domain.com”解析为“xxxx”的 IP 地…

书生·浦语 大模型(学习笔记-9)大模型微调的相关概念 预训练 与 微调 全量微调FFT 与 PEFT的区别

目录 一、什么是大模型微调 二、指令微调 三、微调的目的 三、微调的方式 四、微调的步骤 五、微调数据准备 六、微调的数据质量 一、什么是大模型微调 预训练和微调的区别&#xff0c;这个很关键 二、指令微调 这个地方主要是微调的角度不同&#xff0c;简单理解&#…

(学习日记)2024.04.20:UCOSIII第四十八节:各文件功能概览

之前的章节都是针对某个或某些知识点进行的专项讲解&#xff0c;重点在功能和代码解释。 回到最初开始学μC/OS-III系统时&#xff0c;当时就定下了一个目标&#xff0c;不仅要读懂&#xff0c;还要读透&#xff0c;改造成更适合中国宝宝体质的使用方式。在学完野火的教程后&a…

leetcode-包含min函数的栈-93

题目要求 题目思路 1.设计上两个栈&#xff0c;第一个栈s1里面正常存储插入进来的数据&#xff0c;s2里面只存储s1里面最小的那个数据。 2.对于push函数&#xff0c;所有新来的value都需要在s1中插入&#xff0c;s2中&#xff0c;如果s2为空&#xff0c;那么也直接插入&#x…