ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

三语言实现WebSocket实时推送Demo

三语言实现WebSocket实时推送Demo

1. 写在前面

做后端开发的朋友应该都有过这样的经历:页面上的数据要实时刷新,轮询太浪费资源,长连接又不好维护。后来接触了 WebSocket,才发现这东西确实好用。今天不聊太深的理论,就从一个实际的小需求出发,用 Python、Java、PHP 三种语言分别写一个最简单的推送 Demo,把消息从服务端推到客户端。代码都不长,跑起来就能看到效果。

2. WebSocket 到底解决了什么问题

以前我们做消息推送,最常用的办法就是前端定时去问后端“有没有新消息”,也就是轮询。这种方式实现简单,但服务器压力大,而且消息不及时。WebSocket 不一样,它是一条全双工的通道,服务端可以主动把消息推给客户端,不用等客户端来问。像在线聊天、订单提醒、后台通知这类场景,用 WebSocket 就非常合适。

简单理解,WebSocket 就是让浏览器和服务器之间建立一条“常驻”的管道,两边随时都能往管道里塞数据。下面我们就用三种语言分别搭一条这样的管道。

3. Python 版:用 websockets 库实现

Python 这边我习惯用websockets这个库,安装和写起来都比较顺手。先装依赖:

pip install websockets

然后写一个最简单的服务端,监听 8765 端口,收到客户端连接后主动推一条消息过去:

import asyncio import websockets async def handler(websocket, path): # 客户端连上来之后,主动推送一条消息 await websocket.send("Hello from Python WebSocket!") print("消息已推送") async def main(): async with websockets.serve(handler, "localhost", 8765): print("服务已启动,端口 8765") await asyncio.Future() # 保持运行 if __name__ == "__main__": asyncio.run(main())

客户端这边用浏览器或者写个小脚本都行。用 Python 客户端验证一下:

import asyncio import websockets async def client(): async with websockets.connect("ws://localhost:8765") as ws: msg = await ws.recv() print("收到消息:", msg) asyncio.run(client())

跑起来之后,服务端控制台会打印“消息已推送”,客户端会打印收到的内容。整个流程非常直观。

4. Java 版:用 Spring Boot + WebSocket

Java 这边我用 Spring Boot 来做,因为它在 WebSocket 这块封装得比较成熟,配置也少。先建一个 Spring Boot 项目,引入依赖:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>

然后写一个 WebSocket 配置类,把处理器注册进去:

import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(new PushHandler(), "/push").setAllowedOrigins("*"); } }

再写一个处理器类,客户端连上来之后,服务端主动推送一条消息:

import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler; public class PushHandler extends TextWebSocketHandler { @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { // 连接建立后主动推送 session.sendMessage(new TextMessage("Hello from Java WebSocket!")); System.out.println("消息已推送"); } }

启动项目后,浏览器里打开一个 WebSocket 测试页面,连接ws://localhost:8080/push,就能收到服务端推过来的消息。这里要注意,Spring Boot 默认端口是 8080,如果改了端口记得同步调整连接地址。

5. PHP 版:用 Workerman 实现

PHP 做 WebSocket 一般会借助 Workerman 这个常驻内存框架,它本身对长连接支持得比较好。先通过 Composer 安装:

composer require workerman/workerman

然后写一个简单的服务端脚本,监听 2346 端口,客户端连上来后推送一条消息:

<?php use Workerman\Worker; require_once __DIR__ . '/vendor/autoload.php'; $worker = new Worker("websocket://0.0.0.0:2346"); $worker->onConnect = function ($connection) { // 客户端连上来之后主动推送 $connection->send("Hello from PHP WebSocket!"); echo "消息已推送\n"; }; Worker::runAll();

启动方式也简单,在命令行里执行:

php server.php start

客户端连接ws://localhost:2346就能收到消息。Workerman 的好处是它本身是常驻进程,不用依赖 PHP-FPM,适合做实时推送这类场景。

6. 三种实现放一起对比

语言核心依赖启动方式适用场景
Pythonwebsockets直接运行脚本轻量工具、快速原型
JavaSpring Boot启动 Spring 应用企业级项目、复杂业务
PHPWorkerman命令行常驻进程中小型实时应用

选哪种语言,主要看你的项目技术栈和团队熟悉程度。如果只是做个内部小工具,Python 最省事;如果是正式业务系统,Java 的生态更完整;PHP 项目里想加实时推送,Workerman 是个不错的选择。

7. 踩坑提醒

最后说几个我实际踩过的坑,给大家提个醒。第一,WebSocket 连接是长连接,服务端要注意心跳检测,不然客户端断网了服务端还不知道。第二,跨域问题,浏览器里调试的时候记得把跨域放开,不然连接会被拦下来。第三,生产环境一定要上 SSL,也就是 wss 协议,不然浏览器会拒绝连接。

这几个 Demo 虽然简单,但把核心链路跑通了。后面要做的无非是加上消息广播、用户鉴权、消息持久化这些,思路都是一样的。希望这篇文章能帮刚接触 WebSocket 的朋友少走点弯路。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进