Flutter for OpenHarmony:shelf_web_socket 快速构建 WebSocket 服务端,实现端到端实时通信(WebSocket 服务器) 深度解析与鸿蒙适配指南

Flutter for OpenHarmony:shelf_web_socket 快速构建 WebSocket 服务端,实现端到端实时通信(WebSocket 服务器) 深度解析与鸿蒙适配指南

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net

在这里插入图片描述

前言

在移动应用开发中,我们通常扮演“客户端”的角色,去连接远程的 WebSocket 服务。但有时,我们需要在设备本身运行一个微型服务器,例如用于局域网内的设备发现、P2P 文件传输信令,或者在调试模式下作为数据广播源。

shelf_web_socket 是基于 Dart 标准 Web 服务器框架 shelf 的 WebSocket 处理器。它能让你在 Flutter 应用(包括 OpenHarmony)中轻松启动一个能够处理 WebSocket 连接的 HTTP 服务。

一、核心概念

  • Shelf: Dart 的 Web 服务器中间件管道框架(类似 Express.js)。
  • Handler: 处理请求并返回响应的函数。
  • WebSocketChannel: 下层封装,让 WebSocket 操作像 Stream 一样简单。

建立连接 ws://ip:port

协议升级请求 (Upgrade Request)

升级成功 (Success)

数据流/接收端 (Stream/Sink)

WebSocket 客户端\n(App/浏览器)

鸿蒙应用\n(shelf_web_socket)

处理器 (shelf handler)

通信通道 (WebSocketChannel)

二、集成与基础用法

2.1 添加依赖

dependencies:shelf: ^1.4.0 shelf_web_socket: ^3.0.0 web_socket_channel: ^3.0.0 

2.2 启动基础服务

import'package:shelf/shelf_io.dart'as shelf_io;import'package:shelf_web_socket/shelf_web_socket.dart';import'package:web_socket_channel/web_socket_channel.dart';voidmain()async{// 定义 WebSocket 处理器var handler =webSocketHandler((WebSocketChannel webSocket){ webSocket.stream.listen((message){print('收到消息: $message'); webSocket.sink.add('服务端已收到: $message');});});// 启动服务,监听所有 IP (0.0.0.0)var server =await shelf_io.serve(handler,'0.0.0.0',8080);print('WebSocket 服务已启动: ws://${server.address.host}:${server.port}');}
在这里插入图片描述

三、进阶场景与示例

3.1 示例一:广播消息

实现一个聊天室功能,将一个客户端发来的消息广播给所有连接者。

import'package:shelf_web_socket/shelf_web_socket.dart';import'package:web_socket_channel/web_socket_channel.dart';finalList<WebSocketChannel> _clients =[];var broadcastHandler =webSocketHandler((WebSocketChannel webSocket){ _clients.add(webSocket);print('新客户端连接,当前在线: ${_clients.length}'); webSocket.stream.listen((message){// 广播给其他客户端for(var client in _clients){if(client != webSocket){ client.sink.add(message);}}}, onDone:(){ _clients.remove(webSocket);print('客户端断开,剩余: ${_clients.length}');});});
在这里插入图片描述

3.2 示例二:鉴权校验

在建立连接前检查 Header 中的 Token。

import'package:shelf/shelf.dart';import'package:shelf_web_socket/shelf_web_socket.dart';HandlerauthMiddleware(Handler innerHandler){return(Request request){if(request.headers['Authorization']!='Bearer my_secret_token'){returnResponse.forbidden('未授权访问');}returninnerHandler(request);};}// 使用 Pipeline 组装// var handler = Pipeline().addMiddleware(authMiddleware).addHandler(wsHandler);
在这里插入图片描述

3.3 示例三:处理二进制数据

WebSocket 不仅能传字符串,还能传字节流(如图片片段)。

import'dart:typed_data';var binaryHandler =webSocketHandler((WebSocketChannel webSocket){ webSocket.stream.listen((message){if(message isList<int>){print('收到二进制数据,长度: ${message.length}');// 处理二进制逻辑...}else{print('收到文本: $message');}});});
在这里插入图片描述

四、OpenHarmony 平台适配

4.1 网络权限

作为服务端,你需要监听端口,这同样需要 Internet 权限。

"requestPermissions":[{"name":"ohos.permission.INTERNET"}]

4.2 后台运行限制

移动操作系统通常限制应用在后台运行服务。如果你的 WebSocket 服务需要长期运行,建议在前台 Service 中启动,或仅在 App 前台可见时运行。

五、完整实战示例:局域网即时画板服务端

本示例将在 OpenHarmony 设备上启动一个 WebSocket 服务。任何连接到该服务的客户端(可以是另一个 App 或浏览器)发送的坐标点,都会被广播给其他人,实现多端协同绘图。

5.1 示例代码

import'dart:async';import'dart:io';import'package:flutter/material.dart';import'package:shelf/shelf_io.dart'as shelf_io;import'package:shelf_web_socket/shelf_web_socket.dart';import'package:web_socket_channel/web_socket_channel.dart';voidmain(){runApp(constMaterialApp(home:ServerPage()));}classServerPageextendsStatefulWidget{constServerPage({super.key});@overrideState<ServerPage>createState()=>_ServerPageState();}class _ServerPageState extendsState<ServerPage>{HttpServer? _server;finalList<WebSocketChannel> _sockets =[];finalList<String> _logs =[];String _ipInfo ='获取中...';@overridevoidinitState(){super.initState();_getIpAddress();}Future<void>_getIpAddress()async{try{final interfaces =awaitNetworkInterface.list(type:InternetAddressType.IPv4);final ip = interfaces.first.addresses.first.address;setState(()=> _ipInfo = ip);}catch(e){setState(()=> _ipInfo ='无法获取 IP');}}// 启动服务Future<void>_startServer()async{var handler =webSocketHandler((WebSocketChannel webSocket){ _sockets.add(webSocket);_log('新连接接入'); webSocket.stream.listen((message){_log('广播数据: $message');// 广播坐标数据for(var socket in _sockets){if(socket != webSocket){ socket.sink.add(message);}}}, onDone:(){ _sockets.remove(webSocket);_log('连接断开');});});try{ _server =await shelf_io.serve(handler,InternetAddress.anyIPv4,8080);_log('服务启动于 ws://$_ipInfo:8080');}catch(e){_log('启动失败: $e');}}Future<void>_stopServer()async{await _server?.close(force:true);for(var s in _sockets){await s.sink.close();} _sockets.clear(); _server =null;_log('服务已停止');}void_log(String msg){if(!mounted)return;setState((){ _logs.insert(0,'[${DateTime.now().hour}:${DateTime.now().minute}] $msg');});}@overridevoiddispose(){_stopServer();super.dispose();}@overrideWidgetbuild(BuildContext context){returnScaffold( appBar:AppBar(title:constText('WebSocket Server')), body:Column( children:[Container( padding:constEdgeInsets.all(20), color:Colors.blue[50], child:Column( children:[Text('本机 IP: $_ipInfo', style:constTextStyle(fontSize:18, fontWeight:FontWeight.bold)),constSizedBox(height:10),Row( mainAxisAlignment:MainAxisAlignment.center, children:[ElevatedButton( onPressed: _server ==null? _startServer :null, child:constText('启动服务'),),constSizedBox(width:20),ElevatedButton( style:ElevatedButton.styleFrom(backgroundColor:Colors.red[100]), onPressed: _server !=null? _stopServer :null, child:constText('停止'),),],),],),),constDivider(),Expanded( child:ListView.builder( itemCount: _logs.length, itemBuilder:(context, index)=>ListTile( leading:constIcon(Icons.info_outline, size:16), title:Text(_logs[index], style:constTextStyle(fontSize:14)),),),),],),);}}
在这里插入图片描述

六、总结

通过 shelf_web_socket,我们让 OpenHarmony 手机不仅仅是信息的消费者,更成为了信息的生产者和中转站。

最佳实践

  1. 异常处理:Websocket 连接很容易因网络波动断开,务必处理 onDoneonError
  2. 资源释放:在组件销毁或应用退出时,务必关闭 Server 和所有 Channel连接,防止端口占用。
  3. 心跳机制:为了保持连接活性,建议在应用层实现 Ping/Pong 心跳包。

Read more

融资3000万美元,服务2000+团队!听Dify专家拆解如何把AI从Demo变生产力

融资3000万美元,服务2000+团队!听Dify专家拆解如何把AI从Demo变生产力

整理 | 梦依丹      出品 | ZEEKLOG(ID:ZEEKLOGnews) 近日,开源 AI 应用开发平台 Dify 宣布完成 3000 万美元 Pre-A 轮融资,由红杉领投,GL Ventures、Alt-Alpha Capital、五源资本、瑞穗力合投资和 NYX Ventures 跟投,目前公司估值已达 1.8 亿美元。 这家从“原型工具”杀出来的黑马,如今已服务全球超 140 万台设备、2000+ 团队和 280 家企业(包括马士基、安克创新等),正朝着“全球 AI 应用工作流标准定义者”狂奔。 那么,Dify 是如何用“

By Ne0inhk
SQLAlchemy ORM高级特性:从关联关系到查询优化的企业级实战

SQLAlchemy ORM高级特性:从关联关系到查询优化的企业级实战

目录 📖 摘要 🏗️ 第一章:SQLAlchemy架构深度解析 1.1 三层架构设计 1.2 架构图解 1.3 技术选型指南 🔗 第二章:关联关系实战 2.1 核心关联类型 2.2 加载策略优化 2.3 加载策略性能对比 🔍 第三章:查询优化秘籍 3.1 基础优化技巧 3.2 聚合查询优化 3.3 查询执行流程 🔊 第四章:事件监听机制 4.1 核心事件监听 4.2 业务事件应用 4.3 事件监听架构 🎭 第五章:混合属性实战 5.1

By Ne0inhk
首个多院区异构多活容灾架构,浙人医创新开新篇

首个多院区异构多活容灾架构,浙人医创新开新篇

KingbaseES数据库:首个多院区异构多活容灾架构,浙人医创新开新篇 2025 年 10 月 23 日消息,浙江省人民医院(浙人医)作为省内卫健系统信创 “领头雁”,依托金仓数据库搭建异构多院区多活数据底座,成为国内首个 LIS 国产化异构数据多院区多活改造案例。浙人医拥有多院区及托管分院,此前面临核心系统依赖国外数据库、多院区数据互通难等问题,遂选择 LIS 系统为信创突破口,联合电科金仓实现四大技术创新,达成 RTO≤10min、RPO=0 的 6 级灾容标准,业务连续性达 99.99%。目前 4 大院区数据双向同步,数据调用效率提升 60%,富阳院区还实现全栈信创与业务系统云化部署,为医疗信创提供可复制样本。 作为浙江省卫健系统信创“领头雁”,浙江省人民医院(下称“浙人医”)从LIS系统切入,实现从单系统突破到全栈国产化的跨越式发展。依托金仓数据库搭建的异构多院区多活数据底座,

By Ne0inhk
别再手动调优了!KingbaseES连接条件下推自动拯救慢 SQL

别再手动调优了!KingbaseES连接条件下推自动拯救慢 SQL

告别SQL性能焦虑:金仓数据库“连接条件下推”的性能魔法 你是否遇到过这样的场景:一个看似复杂的SQL,在测试环境运行飞快,一到生产环境就“卡死”,一查执行计划,发现子查询生成了一个巨大的中间结果集,导致后续操作全部陷入性能泥潭? 如果你正被此类场景困扰,那么,是时候认识一项改变游戏规则的技术:金仓数据库(KingbaseES)「基于代价的连接条件下推」。它不仅是技术优化,更是应对复杂业务查询的“性能终结者”。 一、 为什么你的复杂SQL会“爆内存”? 在金融、政务等复杂业务系统中,为了逻辑清晰,SQL常常被写成这样: SELECT * FROM (SELECT DISTINCT * FROM 巨表_A) AS 子查询结果, 筛选表_B WHERE 子查询结果.关键ID = 筛选表_B.关键ID AND 筛选表_B.过滤字段 = '

By Ne0inhk