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

Ollama + Milvus 本地智能体搭建指南:打造本地部署RAG知识库助手(java快速搭建)

前提需要docker环境 本文基于docker安装 Milvus 向量数据库 后台通过java项目启动  java版本17 技术组件核心作用核心优势 Ollama本地运行开源大模型(对话生成、文本向量化)    1. 轻量便捷,一键部署,无需复杂的模型环境配置;    2. 离线可用,支持 Qwen、Llama、Mistral 等多款开源模型;    3. 支持自定义模型,可嵌入固定角色与业务规则;    4. 无调用额度限制,零成本使用。 Milvus存储与检索高维向量数据(知识库核心载体)    1. 专为向量检索设计,性能远超通用数据库,支持百万级向量快速检索;    2. 支持数据持久化,重启服务后知识库数据不丢失;    3. 提供可视化工具 Attu,方便管理向量集合与数据;    4. 可横向扩展,从单机版平滑升级到分布式集群,满足业务增长需求。 Spring AI基于 Spring Boot,简化大模型 / 向量库整合

By Ne0inhk
Java 时间类(中):JDK8 全新时间 API 详细教程

Java 时间类(中):JDK8 全新时间 API 详细教程

🏠个人主页:黎雁 🎬作者简介:C/C++/JAVA后端开发学习者 ❄️个人专栏:C语言、数据结构(C语言)、EasyX、JAVA、游戏、规划、程序人生 ✨ 从来绝巘须孤往,万里同尘即玉京 文章目录 * Java 时间类(中):JDK8 全新时间 API 详细教程 🕘 * 📝 文章摘要 * 🧠 上篇知识回顾 * 一、JDK8 时间类整体架构 🏛 * 二、ZoneId 时区类 🌍 * 1. 核心作用 * 2. 常用方法 * 3. 代码示例 * 三、Instant 时间戳类 ⚡ * 1. 核心作用 * 2. 常用方法 * 3. 代码示例 * 四、ZonedDateTime

By Ne0inhk
Java外功精要(6)——Spring事务及其传播机制

Java外功精要(6)——Spring事务及其传播机制

1.概述 Spring事务管理是Spring框架中用于确保数据库操作 原子性、一致性、隔离性和持久性(ACID) 的核心机制。它通过声明式或编程式(本文略)方式管理事务,支持多种事务传播行为和隔离级别相较于编程式事务,声明式事务通过@Transactional注解实现事务管理,无需手动编写事务代码事务基本概念在全面解析MySQL(5)——“索引、事务、JDBC”三大核心一文中有介绍,本文不再赘述 2.@Transactional 作用:提供声明式事务管理。它简化了在应用程序中管理数据库事务的流程。开发者只需在方法或类上添加此注解,Spring框架就会自动处理事务的开启、提交和回滚,无需手动编写事务管理代码(如 begin、commit、rollback) 级别:类 + 方法作为类注解:为类中所有public方法添加注解作为方法注解:默认仅对public方法生效 @RequestMapping("/test")@RestController@Slf4jpublicclassTestController{privatefinalUserService userService;@A

By Ne0inhk

2分钟一个模块,半小时一个项目!飞算JavaAI专业版实测:真无限Token + 全栈生成

我是Java开发工程师,也自学了大数据相关的组件,如今也在学习AI Agent相关知识,8年前学的后端框架是SSH和SSM和Spring(使用配置文件进行依赖注入),前端就是三驾马车HTML、CSS和JavaScript,工作之后还用过JFinal、Struts2,还有官网不再维护的LayUI。 现在已经是AI盛行的年代了,有聊天的AI、有生成图片的AI、有生成视频的AI,对于程序员来说,仅仅是搜索知识,对工作效率的提升是有限的。 飞算JavaAI专业版实测 * 1. 官网介绍 * 1.1. 再相见 * 1.2. 是噱头还是有真本事? * 1.3. 我工作中的痛点 * 1.4. 飞算JavaAI如何解决问题 * 2. 安装部署 * 2.1. 在线安装 * 2.2. 离线安装 * 3. 五步智能引导测试 * 4. 总结 1. 官网介绍 飞算JavaAI官网:https://feisuanyz.

By Ne0inhk