如何使用Python实现WebScoket

大家好,后端开发领域迅速发展,需要满足今天应用程序多样化需求的协议。默认的HTTP协议设计用于无状态和短生命周期请求,但在需要实时交互的场景中(如实时信令、聊天应用和协同编辑),它显然不够。

为了解决这些局限,开发人员正在探索更好满足现代应用程序动态需求的替代协议。

所有提到的限制都可以通过使用构建在TCP协议之上的WebSocket来克服。让我们深入了解一下它们的一些关键特性。

全双工通信

WebSocket支持同时进行的双向通信,客户端和服务器都可以独立发送消息,无需等待请求-响应周期。

低延迟

WebSocket建立的持久连接显著降低了与传统HTTP连接相比的延迟。这使得WebSocket非常适用于实时应用,如聊天应用、在线游戏、实时通知和协同编辑。

资源有效利用

WebSocket消除了为每次通信重复打开和关闭连接的需要。长寿命的连接减少了建立新连接的开销,提高了资源利用效率。

广泛浏览器支持

现代Web浏览器支持WebSocket,使其成为实时Web应用程序广泛采用的技术。大多数编程语言和Web框架还提供处理WebSocket连接的库或模块。

安全连接

WebSocket可以在安全连接上使用(WebSocket Secure,或WSS),使用与保护HTTPS连接相同的TLS/SSL协议。这确保了通信是加密且安全的。

废话不多说,让我们进入代码。

构建WebSocket通信的最简代码

我使用Tornado,它使我能够轻松实现这一点,只需覆盖现有方法。

服务器端

pip install tornado

让我们首先编写最小的代码。

from typing import Awaitable  import tornado.ioloop  
import tornado.web  
import tornado.websocket  class WebSocketHandler(tornado.websocket.WebSocketHandler):  """  此处理程序类用于处理WebSocket连接。  """  def open(self, *args: str, **kwargs: str) -> Awaitable[None] | None:  """  打开WebSocket连接。  覆盖此方法以处理WebSocket的打开。  当打开新的WebSocket时调用此方法。  """  print("WebSocket已打开")  return super().open(*args, **kwargs)  def on_message(self, message: str | bytes) -> Awaitable[None] | None:  """  处理WebSocket上的传入消息。  覆盖此方法以处理传入的消息。  当收到新的WebSocket消息时调用此方法。  """  print(f"收到消息:{message}")  self.write_message(f"你说:{message}")  def on_close(self) -> None:  """  处理WebSocket的关闭。  覆盖此方法以处理WebSocket的关闭。  当WebSocket关闭时调用此方法。  """  print("WebSocket已关闭")  return super().on_close()  def app() -> tornado.web.Application:  return tornado.web.Application(  [  (r"/websocket", WebSocketHandler),  ]  )  if __name__ == "__main__":  application = app()  application.listen(8080)  print("监听端口8080")  tornado.ioloop.IOLoop.current().start()

代码解析:

  • import tornado.iolooptornado.ioloop模块提供了用于管理异步操作的I/O循环。I/O循环是Tornado非阻塞架构的核心。它异步处理事件,如传入请求和响应,而不阻塞其他任务的执行。
  • import tornado.webtornado.web模块包含用于构建Web应用程序的类和工具。它提供了关键组件,如RequestHandler类,允许您定义如何响应HTTP请求。此模块对于创建Web应用程序的结构、处理路由和处理传入的HTTP请求至关重要。
  • import tornado.websocket:用于处理WebSocket连接的模块。它提供了WebSocketHandler类,允许您定义应用程序如何响应基于WebSocket的通信。
  • tornado.web.Application:入口点,用于将各种处理程序、设置和配置绑定在一起,创建完整的Web应用程序。它接受一个列表,包含**(绑定路径,请求处理程序)**。
  • application.listen(8080):开始在端口8080上监听传入请求。
  • tornado.ioloop.IOLoop.current().start():在当前上下文中启动事件循环,以异步处理请求。

运行WebSocket服务器:

python3 websockets.py

客户端

我使用的是Node而不是浏览器控制台,但您也可以使用浏览器控制台。

对于Node,请首先安装支持WebSocket的库。

npm install ws
const WebSocket = require("ws");  var socket = new WebSocket("ws://localhost:8080/websocket");  socket.on("open", function() {  console.log("连接已打开")  socket.send("你好,服务器!");  
})  socket.on("message", function(message) {  console.log('新消息 ' + message)  if (message.data == 'ping') {  socket.send('pong');  }  
})  socket.on("close", function() {  console.log("连接已关闭...")  
})
如果您尝试在浏览器控制台中运行,则需要将跨源设置为True。class WebSocketHandler(tornado.websocket.WebSocketHandler):  ...      def check_origin(self, origin: str) -> bool:  return True

在浏览器中运行

var socket = new WebSocket("ws://localhost:8080/websocket");  socket.onopen = function(event) {  console.log("WebSocket连接已打开");  socket.send("你好,服务器!");  
};  socket.onmessage = function(event) {  console.log("从服务器接收到消息:", event.data);  
};  socket.onclose = function(event) {  console.log("WebSocket连接已关闭");  
};
WebSocket连接已打开  
VM53:9 从服务器接收到消息:你好,服务器!

第一次翻译:

应用: 基于房间的聊天系统

让我们添加一些代码,实现用户房间和用户名功能。

服务器端代码

from typing import Awaitable  import tornado.ioloop  
import tornado.web  
import tornado.websocket  class ChatRoom:  def __init__(self):  self.clients = set()  def add_client(self, client):  self.clients.add(client)  def remove_client(self, client):  self.clients.remove(client)  def broadcast(self, message, sender=None):  for client in self.clients:  if client.user_name != sender.user_name:  client.write_message(f"{sender.user_name}: {message}")  else:  client.write_message("")  class WebSocketHandler(tornado.websocket.WebSocketHandler):  room_id = None  user_name = None  def open(self, room_id, user_name) -> Awaitable[None] | None:  self.room_id = room_id  self.user_name = user_name  room = self.application.get_or_create_room(self.room_id)  room.add_client(self)  print(f"WebSocket为 {self.user_name} 在房间 {self.room_id} 中打开")  def on_message(self, message: str | bytes) -> Awaitable[None] | None:  print(f"从 {self.user_name} 收到消息:{message}")  room = self.application.get_or_create_room(self.room_id)  room.broadcast(message, sender=self)  def on_close(self) -> None:  print(f"WebSocket为 {self.user_name} 关闭")  self.application.get_or_create_room(self.room_id).remove_client(self)  return super().on_close()  def check_origin(self, origin: str) -> bool:  return True  class ApplicationWithRooms(tornado.web.Application):  def __init__(self, *args, **kwargs):  super().__init__(*args, **kwargs)  self.rooms = {}  def get_or_create_room(self, room_id):  if room_id not in self.rooms:  self.rooms[room_id] = ChatRoom()  return self.rooms[room_id]  def app() -> ApplicationWithRooms:  return ApplicationWithRooms(  [  (r"/websocket/(\w+)/(\w+)", WebSocketHandler),  ]  )  if __name__ == "__main__":  application = app()  application.listen(8080)  print("监听端口8080")  tornado.ioloop.IOLoop.current().start()

代码解析:

  • ChatRoom: 这个类管理客户端。即添加、删除客户端和向同一房间中的所有客户端广播消息。
  • WebSocketHandler: 我们修改了现有的处理程序以将新客户端添加到房间中,在收到新消息时在创建房间之前广播消息。
  • ApplicationWithRooms: 我们用这个类替换了默认的Application,只是为了处理聊天室逻辑。
  • /websocket/(\w+)/(\w+): 处理程序URL也已更改,以在URL中接收聊天室和用户ID。

客户端代码

客户端代码也已更新,以在连接后提示发送消息到网络。

const WebSocket = require("ws");  
const readline = require("readline");  const rl = readline.createInterface({  input: process.stdin,  output: process.stdout  
})  function generate_random_name() {  let name = "";  for (let i = 0; i < 5; i++) {  name += String.fromCharCode(97 + Math.floor(Math.random() * 26))  };  return name;  
}  var username = generate_random_name();  const room_id = "room1";  var socket = new WebSocket(`ws://localhost:8080/websocket/${room_id}/${username}`);  socket.on("open", function () {  console.log("已连接到房间 " + room_id + "!")  rl.setPrompt(`${username} >> `);  rl.prompt();  rl.on("line", function (line) {  if (line === "exit") {  socket.close();  return;  }  socket.send(line);  })  
})  socket.on("message", function (message) {  if (message.length > 0) {  console.log('[' + '' + message + ']')  }  rl.prompt();  
})  socket.on("close", function () {  console.log("连接已关闭...")  rl.close();  
})

好了,这就是最小代码实现,你可以上手运行一下,看看实际效果。

总结

虽然提供的示例展示了使用WebSocket的基本功能,但值得注意的是,生产级别的WebSocket应用程序需要更全面的方法。

必须仔细实现强大的授权、安全的身份验证机制和其他重要的考虑因素,以确保您的实时通信解决方案的安全性、可扩展性和可靠性。

始终根据最佳实践和安全标准调整WebSocket实现,以满足生产环境的多样化要求。

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

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

相关文章

Python自动化测试框架整理,搭建框架看这篇就够了。。

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;薪资嘎嘎涨 什么是测试框架呢&#xff1f; 框架是一组准则&#xff0c;一个体系结构&#xff0c;遵循这些…

PHP微信UI在线聊天系统源码 客服私有即时通讯系统

(购买本专栏可免费下载栏目内所有资源不受限制,持续发布中,需要注意的是,本专栏为批量下载专用,并无法保证某款源码或者插件绝对可用,介意不要购买) DuckChat是一套完整的私有即时通讯解决方案,包含服务器端程序和各种客户端程序(包括iOS、Android、PC等)。通过Duck…

深入了解RabbitMQ:构建高效的消息队列系统

目录 1、RabbitMQ简介 1.1 什么是消息队列系统 1.2 RabbitMQ的概述 1.3 RabbitMQ的优势和适用场景

python查询xml类别

第一章 导包 import os from xml.etree.ElementTree import ElementTree第二章 存储类别 # 定义一个空集合用于存储类别 classes set()第三章 遍历所有XML文件 # 遍历指定目录下的所有XML文件 for filename in os.listdir(/home/li/PycharmProjects/Annotations):if filena…

kubeadm安装K8S_v1.28.x容器使用docker

一&#xff0e;环境部署 1.1 基础环境配置&#xff08;只有1台服务器&#xff0c;作为masrer&#xff0c;也作为node使用&#xff09; [rootecs-cf5e ~]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) [rootecs-cf5e ~]# uname -a Linux ecs-cf5e 3.10.0-11…

[ECE] Error Codes: Parity Bit and Cyclic Redundancy Check

当我们在数字通信中传输数据时&#xff0c;可能会发生错误&#xff0c;而错误检测码&#xff08;Error Codes&#xff09;是一种用于检测和纠正这些错误的技术。两种常见的错误检测码是奇偶校验位&#xff08;Parity Bit&#xff09;和循环冗余检测&#xff08;Cyclic Redundan…

LRU缓存(Leetcode146)

例题&#xff1a; 分析&#xff1a; 题目要求函数get和put要达到O(1)的时间复杂度&#xff0c;可以用 hashMap 来实现&#xff0c;因为要满足逐出最久未使用的元素的一个效果&#xff0c;还需要配合一个双向链表来共同实现。链表中的节点为一组key-value。 我们可以用双向链表来…

分割头篇 | 原创自研 | YOLOv8 更换 SEResNeXtBottleneck 头 | 附详细结构图

左图:ResNet 的一个模块。右图:复杂度大致相同的 ResNeXt 模块,基数(cardinality)为32。图中的一层表示为(输入通道数,滤波器大小,输出通道数)。 1. 思路 ResNeXt是微软研究院在2017年发表的成果。它的设计灵感来自于经典的ResNet模型,但ResNeXt有个特别之处:它采用…

FileZilla 的安装与使用

目录 一. FileZilla 是什么二. FileZilla 的安装1. 下载 FileZilla2. 安装 三. FileZilla 的使用 一. FileZilla 是什么 FileZilla 是一个免费的开源 FTP&#xff08;文件传输协议&#xff09;客户端软件&#xff0c;用于在计算机之间传输文件。它提供了一个直观的用户界面&am…

SV-9032 机架式ip网络采播器

SV-9032是深圳锐科达电子有限公司的一款机架式网络采播器&#xff0c;具有10/100M以太网接口&#xff0c;后面板上有一组AUX音源输入和一组6.35mm接口的麦克风输入&#xff0c;可以直接连接音源输出设备或麦克风&#xff0c;将采集音源编码后发送至网络播放终端上。同时还具有三…

数据结构之生成树及最小生成树

数据结构之生成树及最小生成树 1、生成树概念2、最小生成树 数据结构是程序设计的重要基础&#xff0c;它所讨论的内容和技术对从事软件项目的开发有重要作用。学习数据结构要达到的目标是学会从问题出发&#xff0c;分析和研究计算机加工的数据的特性&#xff0c;以便为应用所…

Springboot+vue的健身房管理系统(有报告)。Javaee项目,springboot vue前后端分离项目

演示视频&#xff1a; Springbootvue的健身房管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的前后端分离的健身房管理系统&#xff0c;采用M&#xff08;model&#xf…

【SparkML系列2】DataSource读取图片数据

DataSource(数据源) 在本节中&#xff0c;我们将介绍如何在机器学习中使用数据源加载数据。除了一些通用的数据源&#xff0c;如 Parquet、CSV、JSON 和 JDBC 外&#xff0c;我们还提供了一些专门用于机器学习的数据源。 ###Image data source&#xff08;图像数据源&#xf…

配置nginx以成功代理websocket

配置nginx以成功代理websocket 在使用socket.io的时候遇到这样一个问题&#xff1a;websocket接收的消息的顺序错位了&#xff0c;然后看了一下浏览器的console的报错&#xff0c;提示连接到ws失败&#xff0c;然后在浏览器的开发者工具的网络中看了一下ws对应的消息里面报错&…

RabbitMQ概念

一 、RabbitMQ概念 1 架构图 2 相关概念 Publisher - ⽣产者&#xff1a;发布消息到RabbitMQ中的Exchange Consumer - 消费者&#xff1a;监听RabbitMQ中的Queue中的消息 Broker&#xff1a;接收和分发消息的应用&#xff0c;RabbitMQ Server就是 Message Broker&#xf…

循环——枚举算法2(c++)

目录 找和为K的两个元素 描述 在一个长度为n(n < 1000)的整数序列中&#xff0c;判断是否存在某两个元素之和为k。 输入 第一行输入序列的长度n和k&#xff0c;用空格分开。 第二行输入序列中的n个整数&#xff0c;用空格分开。 输出 如果存在某两个元素的和为k&…

Oracle PL/SQL Programming 第4章:Language Fundamentals 读书笔记

总的目录和进度&#xff0c;请参见开始读 Oracle PL/SQL Programming 第6版 本章介绍两种类型的 PL/SQL 控制语句&#xff1a;条件控制语句和顺序控制语句。 几乎您编写的每一段代码都需要条件控制&#xff0c;即根据条件指导程序执行流程的能力。 您可以使用 IF-THEN-ELSE 和…

Java基于SpringBoot+Vue的网上超市管理系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

C++类和对象(中)六个默认成员函数

&#x1f308;类的六个默认成员函数 任何一个类&#xff0c;不管是否为空&#xff0c;都会在生成的时候默认调用六个成员函数&#xff0c;这些成员函数可以自动生成&#xff0c;也可以由程序员写出。这六个默认成员函数分别是&#xff1a; 最主要的是前四个&#xff1a; 初始…

༺༽༾ཊ—Unity之-02-抽象工厂模式—ཏ༿༼༻

首先创建一个项目&#xff0c; 在这个初始界面我们需要做一些准备工作&#xff0c; 建基础通用文件夹&#xff0c; 创建一个Plane 重置后 缩放100倍 加一个颜色&#xff0c; 任务&#xff1a;使用 抽象工厂模式 创建 人物与宠物 模型&#xff0c; 首先资源商店下载 人物与宠物…