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

国产化服务器部署:银河麒麟系统搭建 Web 服务实战

一、前言 在国产化替代浪潮下,政企单位对服务器硬件、操作系统的国产化适配需求日益迫切。银河麒麟操作系统(Kylin OS)作为国内自主研发的主流服务器操作系统,凭借其高安全性、稳定兼容性和完善的国产化生态支持,成为服务器部署的核心选择之一。 Web 服务作为企业数字化转型的基础载体,广泛应用于内部办公系统、业务展示平台、国产化应用发布等场景。本文将聚焦 “银河麒麟服务器版搭建 Web 服务” 的全流程实战,从环境准备、软件安装、配置优化到访问测试,一步步带大家实现国产化服务器的 Web 服务部署,同时规避常见坑点,兼顾实用性与国产化适配特性。 本文适用于银河麒麟服务器版(推荐 Kylin Server V10 SP3),以主流的 Nginx 作为 Web 服务器软件(轻量化、高性能,适配国产化芯片架构),全程提供可直接复制的命令和配置示例,零基础也能快速上手。 二、前期准备 2.1

【JavaEE】创建SpringBoot第一个项目,Spring Web MVC⼊⻔,从概念到实战的 Web 开发进阶之旅

【JavaEE】创建SpringBoot第一个项目,Spring Web MVC⼊⻔,从概念到实战的 Web 开发进阶之旅

💬 欢迎讨论:如对文章内容有疑问或见解,欢迎在评论区留言,我需要您的帮助! 👍 点赞、收藏与分享:如果这篇文章对您有所帮助,请不吝点赞、收藏或分享,谢谢您的支持! 🚀 传播技术之美:期待您将这篇文章推荐给更多对需要学习JavaEE语言、低代码开发感兴趣的朋友,让我们共同学习、成长! 1.什么是 Spring Web MVC? 官⽅对于 Spring MVC 的描述是这样的: Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning.

WebView 并发初始化竞争风险分析

WebView 并发初始化竞争风险分析

1. 问题背景 本次验证聚焦以下场景: * 后台线程异步调用 WebSettings.getDefaultUserAgent() * 主线程在冷启动阶段首次调用 new WebView() * 两者并发进入 WebView provider / Chromium 初始化链 目标不是验证“预热是否一定提速”,而是确认: * 是否存在共享初始化链竞争 * 主线程是否会因此被拖慢或阶段性阻塞 * 是否具备演化为 ANR 的风险 2. 关键修正结论 结合当前所有日志,更准确的结论应为: getDefaultUserAgent() 与首次 new WebView() 并发时,二者并不是始终“卡死”在 WebViewFactory.getProvider() 这一行;更真实的表现是:它们会共享同一条 WebView provider / Chromium 初始化链,在不同阶段交错推进,并在部分关键节点出现阶段性等待、锁竞争或串行化,进而放大主线程耗时。 也就是说,问题本质更接近: * 交错执行

DeerFlow基础教程:DeerFlow控制台UI与Web UI双模式使用详解

DeerFlow基础教程:DeerFlow控制台UI与Web UI双模式使用详解 1. DeerFlow是什么:你的个人深度研究助理 你有没有过这样的经历?想快速了解一个新领域,比如“量子计算在金融建模中的最新应用”,但搜了一堆资料,发现信息零散、真假难辨、专业门槛高,最后只能放弃?或者需要为一次重要汇报准备一份结构清晰、数据扎实、有深度分析的行业报告,却卡在资料收集和逻辑梳理上,耗时又费力? DeerFlow就是为解决这类问题而生的。它不是另一个聊天机器人,而是一个能真正帮你“做研究”的AI助手——你的个人深度研究助理。 它不满足于简单回答问题,而是主动调用搜索引擎获取最新信息、运行Python代码验证假设、调用专业工具分析数据、整合多源内容生成结构化报告,甚至能把研究成果变成一段自然流畅的播客音频。整个过程就像你请了一支由研究员、数据分析师、文案编辑和播客制作人组成的虚拟团队,在后台协同工作。 更关键的是,它把这一切复杂能力,封装成了两种你随时可以打开、上手就用的界面:一个简洁高效的命令行控制台(Console UI),适合喜欢直接、快速、可复现操作的用户;还有一个功能