当前位置:   article > 正文

websocket 单点通信,广播通信

websocket 单点通信,广播通信

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

参考:

HTML5 WebSocket | 菜鸟教程

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

应用场景:

        html单点通信

        消息群发

        聊天室功能

一,单点通信

      1,server.py

  1. import asyncio
  2. import websockets
  3. from datetime import datetime
  4. async def handler(websocket):
  5. data = await websocket.recv()
  6. reply = f"收到数据:{data} time: {datetime.now()}"
  7. print(reply)
  8. await websocket.send(reply)
  9. print("Send reply")
  10. async def main():
  11. async with websockets.serve(handler, "localhost", 9999):
  12. await asyncio.Future() # run forever
  13. if __name__ == "__main__":
  14. asyncio.run(main())

        2,python 客户端 client.py

  1. import asyncio
  2. import websockets
  3. import time
  4. async def ws_client(url):
  5. for i in range(1, 40):
  6. async with websockets.connect(url) as websocket:
  7. await websocket.send("Hello, I'm client 1")
  8. response = await websocket.recv()
  9. print(response)
  10. time.sleep(3)
  11. if __name__ == "__main__":
  12. asyncio.run(ws_client('ws://127.0.0.1:9999'))

        3,html客户端client.html

  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>websocket demo</title>
  6. <meta name="viewport" content="width=device-width, initial-scale=1">
  7. <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/css/bootstrap.min.css">
  8. <script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"> </script>
  9. <script src="https://cdn.staticfile.org/popper.js/1.15.0/umd/popper.min.js"></script>
  10. <script src="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
  11. <script type="text/javascript">
  12. async function wsClient(url) {
  13. for (let i = 1; i <= 40; i++) {
  14. const websocket = new WebSocket(url);
  15. // Wait for the WebSocket connection to open
  16. await new Promise((resolve, reject) => {
  17. websocket.addEventListener('open', () => {
  18. resolve();
  19. });
  20. websocket.addEventListener('error', reject);
  21. });
  22. // Send a message to the server
  23. websocket.send("Hello, I'm client html");
  24. // Wait for a response from the server
  25. const response = await new Promise((resolve) => {
  26. websocket.addEventListener('message', (event) => {
  27. resolve(event.data);
  28. });
  29. });
  30. // Print the response
  31. console.log(response);
  32. // Wait for 3 seconds before sending the next message
  33. await new Promise(resolve => setTimeout(resolve, 1000));
  34. // Close the WebSocket connection before the next iteration
  35. websocket.close();
  36. }
  37. }
  38. // Call the function with the desired WebSocket URL
  39. wsClient('ws://127.0.0.1:9999');
  40. </script>
  41. </head>
  42. <body>
  43. </body>
  44. </html>

        4,启动  :

        python server.py

        python client.py       

         

        打开client.html

二,广播消息

        1,server.py

  1. import asyncio
  2. import websockets
  3. from datetime import datetime,time
  4. # 维护一个连接的客户端字典,key为remote_address
  5. connected_clients = {}
  6. # 处理连接事件
  7. async def connection_handler(websocket, path):
  8. remote_address = websocket.remote_address
  9. print(f"新连接建立 from {remote_address}")
  10. connected_clients[remote_address] = websocket # 使用remote_address作为key添加到字典中
  11. print(f"当前连接数:{len(connected_clients)}")
  12. print(f"连接地址:{list(connected_clients.keys())}")
  13. try:
  14. while True:
  15. await message_handler(websocket)
  16. except websockets.exceptions.ConnectionClosedOK:
  17. print(f"连接已正常关闭 from {remote_address}")
  18. print(f"当前连接地址:{list(connected_clients.keys())}")
  19. finally:
  20. del connected_clients[remote_address] # 连接关闭时从字典中移除
  21. # 处理接收到的消息,并广播出去
  22. async def message_handler(websocket):
  23. data = await websocket.recv()
  24. reply = f"收到数据:{data} time: {datetime.now().time()}"
  25. print(reply)
  26. # 广播消息给所有连接的客户端
  27. for client_websocket in connected_clients.values():
  28. if client_websocket != websocket: # 避免给自己发送消息
  29. try:
  30. await client_websocket.send(reply)
  31. except websockets.exceptions.ConnectionClosedError:
  32. # 如果某个客户端连接已经关闭,由于字典的key-value特性,无需显式移除
  33. print(f"一个连接已关闭,自动从字典中移除")
  34. print("Broadcast reply sent")
  35. async def main():
  36. async with websockets.serve(connection_handler, "localhost", 9999):
  37. await asyncio.Future() # run forever
  38. if __name__ == "__main__":
  39. asyncio.run(main())

        2,client.py

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

        3,html

  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>websocket demo</title>
  6. <meta name="viewport" content="width=device-width, initial-scale=1">
  7. <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/css/bootstrap.min.css">
  8. <script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"> </script>
  9. <script src="https://cdn.staticfile.org/popper.js/1.15.0/umd/popper.min.js"></script>
  10. <script src="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
  11. <script type="text/javascript">
  12. var ws; // 在更宽的作用域定义WebSocket实例
  13. function WebSocketTest() {
  14. if ("WebSocket" in window) {
  15. ws = new WebSocket("ws://127.0.0.1:9999/handler"); // 打开WebSocket连接
  16. ws.onopen = function () {
  17. ws.send("html login");
  18. console.log("发送消息(html login)");
  19. };
  20. ws.onclose = function () {
  21. console.log("连接已关闭...");
  22. };
  23. } else {
  24. alert("您的浏览器不支持 WebSocket!");
  25. }
  26. }
  27. // 新增函数,用于发送消息
  28. function sendMessage() {
  29. if (ws && ws.readyState === WebSocket.OPEN) { // 确保WebSocket已连接且处于OPEN状态
  30. var msgInput = document.getElementById("msgInput"); // 假设有一个输入框用于输入消息
  31. var msg = msgInput.value || "默认消息内容";
  32. ws.send(msg);
  33. console.log("发送消息:" + msg);
  34. msgInput.value = ""; // 清空输入框
  35. } else {
  36. console.warn("WebSocket未连接或非OPEN状态,无法发送消息。");
  37. }
  38. }
  39. </script>
  40. </head>
  41. <body>
  42. <div class="col-md-6 m-5 p-2" id="div_ws">
  43. <a class="btn btn-primary" href="javascript:WebSocketTest()">登录WebSocket</a>
  44. </div>
  45. <div class="col-md-6 m-5 p-2" id="div_ws">
  46. <a class="btn btn-primary" onclick="sendMessage()" >发送消息</a>
  47. </div>
  48. <div class="input-group input-group-lg">
  49. <div class="input-group-prepend">
  50. <span class="input-group-text" id="inputGroup-sizing-lg">消息</span>
  51. </div>
  52. <input type="text" id="msgInput" class="form-control" aria-label="Sizing example input" aria-describedby="inputGroup-sizing-lg" placeholder="请输入消息内容..." >
  53. </div>
  54. </body>
  55. </html>

      4,终端启动服务端 

        python server.py

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

                python client.py   

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

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

三,html 聊天室功能

        1,server.py 

        启动服务端 python server.py

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

      2,  client.html

  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>websocket demo</title>
  6. <meta name="viewport" content="width=device-width, initial-scale=1">
  7. <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/css/bootstrap.min.css">
  8. <script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"> </script>
  9. <script src="https://cdn.staticfile.org/popper.js/1.15.0/umd/popper.min.js"></script>
  10. <script src="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
  11. <script type="text/javascript">
  12. var ws; // 在更宽的作用域定义WebSocket实例
  13. function WebSocketTest() {
  14. if ("WebSocket" in window) {
  15. ws = new WebSocket("ws://127.0.0.1:9999/handler"); // 打开WebSocket连接
  16. ws.onopen = function () {
  17. ws.send("html login");
  18. console.log("发送消息(html login)");
  19. };
  20. ws.onmessage = function (event) { // 添加消息接收处理器
  21. var receivedMsg = document.getElementById("receivedMsg"); // 获取用于显示消息的元素
  22. receivedMsg.innerHTML += "<br>" + event.data; // 将接收到的消息追加到元素中
  23. console.log("接收到消息:" + event.data);
  24. };
  25. ws.onclose = function () {
  26. console.log("连接已关闭...");
  27. };
  28. } else {
  29. alert("您的浏览器不支持 WebSocket!");
  30. }
  31. }
  32. // 新增函数,用于发送消息
  33. function sendMessage() {
  34. if (ws && ws.readyState === WebSocket.OPEN) { // 确保WebSocket已连接且处于OPEN状态
  35. var msgInput = document.getElementById("msgInput"); // 假设有一个输入框用于输入消息
  36. var msg = msgInput.value || "默认消息内容";
  37. ws.send(msg);
  38. console.log("发送消息:" + msg);
  39. msgInput.value = ""; // 清空输入框
  40. } else {
  41. console.warn("WebSocket未连接或非OPEN状态,无法发送消息。");
  42. }
  43. }
  44. </script>
  45. </head>
  46. <body>
  47. <div class="col-md-6 m-5 p-2" id="div_ws">
  48. <a class="btn btn-primary" href="javascript:WebSocketTest()">登录WebSocket</a>
  49. </div>
  50. <div class="col-md-6 m-5 p-2" id="div_ws">
  51. <a class="btn btn-primary" onclick="sendMessage()">发送消息</a>
  52. </div>
  53. <div class="input-group input-group-lg">
  54. <div class="input-group-prepend">
  55. <span class="input-group-text" id="inputGroup-sizing-lg">消息</span>
  56. </div>
  57. <input type="text" id="msgInput" class="form-control" aria-label="Sizing example input"
  58. aria-describedby="inputGroup-sizing-lg" placeholder="请输入消息内容...">
  59. </div>
  60. <div class="col-md-12 m-5 p-2" id="receivedMsg" style="height: 200px;overflow-y: scroll;">
  61. 消息记录区:
  62. </div>
  63. </body>
  64. </html>

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

       客户端1,

客户端2,

客户端3,

四,单人聊天功能分析

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

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

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/524664
推荐阅读
相关标签
  

闽ICP备14008679号