栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 网络技术 > 网络管理

HarmonyOS Sample之NetworkManagement网络管理功能

网络管理 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力



想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

1.介绍

本示例演示了如何使用网络管理模块相关接口,演示了以下功能:

功能1:使用默认网络,打开连接,发送HTTP请求。

功能2:统计指定UID的上行/下行流量。

功能3:使用Socket方式实现不同设备间通信。

此功能需要打开WIFI,并且通信的设备连接相同的WIFI 组成局域网。

操作上,先启动服务端,再启动客户端,然后从客户端发送消息,查看服务端是否收到消息。

功能4:HTTP缓存的使用,创建缓存,供下一次请求使用,减少数据流量和加载时间。

注意,需要以下权限:

ohos.permission.GET_NETWORK_INFO 获取网络连接信息。

ohos.permission.SET_NETWORK_INFO 修改网络连接状态。

ohos.permission.INTERNET 允许程序打开网络套接字,进行网络连接。

详情见官方文档 网络管理开发概述

2.搭建环境

安装DevEco Studio,详情请参考DevEco Studio下载。

设置DevEco Studio开发环境,DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:

如果可以直接访问Internet,只需进行下载HarmonyOS SDK操作。

如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考配置开发环境。

下载源码后,使用DevEco Studio 打开项目,模拟器运行即可。

真机运行需要将config.json中的buddleName修改为自己的,如果没有请到AGC上进行配置,参见 使用模拟器进行调试

3.代码结构 3.1 代码结构

HarmonyOS Sample 之 NetworkManagement 网络管理功能-鸿蒙HarmonyOS技术社区

3.2 相关文件介绍

核心类:

HttpURLConnection.java //支持 HTTP 特定功能的 URLConnection

URLConnection.java //URL连接

URL.java //指向万维网上“资源”的指针

NetStatusCallback.java //网络状态的回调类,出现可用网络触发onAvailable函数

DataFlowStatistics.java //该类提供查询指定蜂窝网络、应用和网卡的整体流量统计和流量统计的接口。

DatagramSocket.java //此类表示用于发送和接收数据报包的套接字。

DatagramPacket.java //数据报包

WifiDevice.java //该类提供Wi-Fi管理接口

NetManager.java //提供接口来管理和使用数据网络。

NetHandle.java // 数据网络

InetAddress.java //网络IP地址

HttpResponseCache.java //该类缓存 HTTP 和 HTTPS 响应以供重用

自定义的类:

ThreadPoolUtil.java //线程池工具类

MainAbilitySlice.java //主页面

NetRequestSlice.java //网络请求&流量统计 功能页

SocketClientSlice.java //Socket客户端

SocketServerSlice.java //Socket服务端

HttpCacheSlice.java //HTTP缓存功能页

页面布局:

http_cache_slice.xml //HTTP缓存示例页

net_request.slice.xml //HTTP请求页面

socket_client_slice.xml //Socket通信客户端页

socket_server_slice.xml //Socket通信服务端页

main_ability_slice.xml //主页面

4.实例讲解 4.1.界面布局




HarmonyOS Sample 之 NetworkManagement 网络管理功能-鸿蒙HarmonyOS技术社区


HarmonyOS Sample 之 NetworkManagement 网络管理功能-鸿蒙HarmonyOS技术社区

4.2.后台代码

4.2.1 NetRequestSlice.java 网络请求&流量统计 功能

a.初始化网络管理对象NetManager

//初始化网络管理对象 
  • netManager = NetManager.getInstance(null); 
  • b.通过线程池获取一个新线程处理进行连接请求

    获取默认数据网络的时候需要ohos.permission.GET_NETWORK_INFO权限。

    //用线程池的取一个新线程处理 
  • ThreadPoolUtil.submit(() -> {     HiLog.debug(LABEL_LOG, "%{public}s", "ThreadPoolUtil submit"); 
  •     //获取默认的数据网络,wifi和流量都关闭时,netId==0,其它时 netId=390/391, must have the ohos.permission.GET_NETWORK_INFO permission     NetHandle netHandle = netManager.getDefaultNet(); 
  •     //接收默认数据网络的状态更改的回调     netManager.addDefaultNetStatusCallback(callback); 
  •      //netManager.setAppNet(netHandle); 
  •      //支持 HTTP 特定功能的 URLConnection。 
  •     HttpURLConnection connection = null;     //输出流 
  •     try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {         //请求的URL 
  •         String urlString = inputText.getText();  
  •         URL url = new URL(urlString);         //使用 netHandle打开URL连接,不使用代理 
  •         URLConnection urlConnection = netHandle.openConnection(url, java.net.Proxy.NO_PROXY);         HiLog.debug(LABEL_LOG, "%{public}s", "netHandle openConnection"); 
  •         //强转换类型         if (urlConnection instanceof HttpURLConnection) { 
  •             connection = (HttpURLConnection) urlConnection;         } 
  •         //请求类型         connection.setRequestMethod("GET"); 
  •         //连接         connection.connect(); 
  •         //流量统计         trafficDataStatistics(false); 
  •          try (InputStream inputStream = urlConnection.getInputStream()) { 
  •             byte[] cache = new byte[2 * 1024];             int len = inputStream.read(cache); 
  •             while (len != -1) {                 // 
  •                 outputStream.write(cache, 0, len);                 len = inputStream.read(cache); 
  •             }         } catch (IOException e) { 
  •             HiLog.error(LABEL_LOG, "%{public}s", "netRequest inner IOException");         } 
  •         //返回结果         String result = new String(outputStream.toByteArray()); 
  •          //UI显示 
  •         getUITaskDispatcher().asyncDispatch(() -> outText.setText(result));         //统计完毕 
  •         trafficDataStatistics(true);  
  •     } catch (IOException e) {         HiLog.error(LABEL_LOG, "%{public}s", "netRequest IOException"); 
  •     } }); 
  • c.按照应用ID,进行数据流量统计

    在发送请求前获取一次,在请求完成后获取一次,

    gitee代码中这个地方有一处笔误,tx代表上行流量,rx代表下行流量才对。详情见官方文档说明 流量统计。

     
  •   private void trafficDataStatistics(boolean isStart) {       int uid = 0; 
  •       try {           //根据给定的包名称和用户 ID 获取应用程序 UID。 
  •           uid = getBundleManager().getUidByBundleName(getBundleName(), 0);       } catch (RemoteException e) { 
  •           HiLog.error(LABEL_LOG, "%{public}s", "trafficDataStatistics RemoteException");       } 
  •       if (isStart) {           //获取指定UID的下行流量。 
  •           rx = DataFlowStatistics.getUidRxBytes(uid);           //获取指定UID的上行流量。 
  •           tx = DataFlowStatistics.getUidTxBytes(uid);       } else { 
  •           rx = DataFlowStatistics.getUidRxBytes(uid) - rx;           tx = DataFlowStatistics.getUidTxBytes(uid) - tx; 
  •            //设置UI显示 
  •           getUITaskDispatcher().asyncDispatch(() -> statisticsText.setText(                   "TrafficDataStatistics:" + System.lineSeparator() 
  •                           + "Receive traffic:" + rx + System.lineSeparator()                           + "Sent traffic:" + tx)); 
  •       }   } 
  • 4.2.2 SocketClientSlice.java/SocketServerSlice.java Socket客户端/服务端

    实现Socket通信,是要客户端和服务端的,服务端在指定网卡上监听指定端口,客户端向指定IP指定端口发送数据,实现通信。

    a.Socket服务端开启监听,等待接收数据

    //监听端口 
  • private static final int PORT = 8888;  
  •  private void startServer(Component component) { 
  •     HiLog.debug(LABEL_LOG, "startServer");      
  •     //线程池获取新线程处理     ThreadPoolUtil.submit(() -> { 
  •         //在指定端口开启监听         try (DatagramSocket socket = new DatagramSocket(PORT)) { 
  •             //数据报包             DatagramPacket packet = new DatagramPacket(new byte[255], 255); 
  •             //死循环接收数据             while (true) { 
  •                 //接收数据                 socket.receive(packet); 
  •                                  //通过专有线程同步设置要显示接收到的数据 
  •                 getUITaskDispatcher().syncDispatch(() -> outText.setText(                         "Receive a message from :" + packet.getAddress().getHostAddress() 
  •                                 + System.lineSeparator() + " on port " + packet.getPort()                                 + System.lineSeparator() + "message :" + new String( 
  •                                 packet.getData()).substring(0, packet.getLength())                 )); 
  •                 packet.setLength(255);  
  •                 //延迟一下,留出处理数据的时间                 Thread.sleep(1000); 
  •             }         } catch (IOException | InterruptedException e) { 
  •             e.printStackTrace();             HiLog.error(LABEL_LOG, "%{public}s", "StartServer  IOException | InterruptedException" + e); 
  •         }     }); 
  • }  
  •   
  • private String getLocationIpAddress() {     HiLog.debug(LABEL_LOG, "getLocationIpAddress"); 
  •     //提供接口来管理 Wi-Fi。     WifiDevice wifiDevice = WifiDevice.getInstance(this); 
  •     HiLog.debug(LABEL_LOG, "wifiDevice:" + wifiDevice);     //WifiLinkedInfo提供有关 Wi-Fi 连接的信息。 
  •     Optional linkedInfo = wifiDevice.getLinkedInfo();     HiLog.debug(LABEL_LOG, "linkedInfo:" + linkedInfo); 
  •     //获取IP地址     int ip = linkedInfo.get().getIpAddress(); 
  •     HiLog.debug(LABEL_LOG, "ip:" + ip);     return (ip & 0xFF) + "." + ((ip >> 8) & 0xFF) + "." + ((ip >> 16) & 0xFF) + "." + (ip >> 24 & 0xFF); 
  • b.Socket客户端发送数据,等待接收数据

    初始化NetManager对象->new 一个DatagramSocket->获取当前数据网络NetHandle->获取服务端的IP地址对象InetAddress

    ->将DatagramSocket绑定到NetHandle -> new 一个数据报包DatagramPacket -> 发送数据

    //通信端口 
  • private static final int PORT = 8888;  
  •   private void netRequest(Component component) { 
  •     HiLog.debug(LABEL_LOG, "netRequest");     //启动新线程 
  •     ThreadPoolUtil.submit(() -> {         //初始化网络管理对象 
  •         NetManager netManager = NetManager.getInstance(null);  
  •         //检查默认数据网络是否已激活。         if (!netManager.hasDefaultNet()) { 
  •             return;         } 
  •         //new套接字         try (DatagramSocket socket = new DatagramSocket()) { 
  •             //获取当前数据网络             NetHandle netHandle = netManager.getDefaultNet(); 
  •              //获取服务端的IP地址 
  •             InetAddress address = netHandle.getByName(inputText.getText());             //将套接字绑定到当前网络 
  •             netHandle.bindSocket(socket);             byte[] buffer = "I'm from Client".getBytes(); 
  •             //数据包             DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, PORT); 
  •             //发送数据             socket.send(request); 
  •             HiLog.debug(LABEL_LOG, "send socket");         } catch (IOException e) { 
  •             e.printStackTrace();             HiLog.error(LABEL_LOG, "%{public}s", "netRequest IOException"+e); 
  •         }     }); 
  • 4.2.3 HttpCacheSlice.java HTTP缓存功能

    应用重复打开一个相同网页时,可以优先从缓存文件里读取内容,从而减少数据流量,降低设备功耗,提升应用性能。

    问:如何设置优先从缓存文件里读取内容,

    答:不用额外设置,自动的 ~~

    设置缓存,需要考虑 缓存位置和缓存大小。

    a.初始化缓存 install

     private void initCache(Component component) { 
  •     //默认的缓存目录     File httpCacheDir = new File(this.getCacheDir(), "http"); 
  •     //缓存大小     long httpCacheSize = 10 * 1024 * 1024; 
  •     try {         //配置缓存目录及最大缓存空间 
  •         HttpResponseCache.install(httpCacheDir, httpCacheSize);         HiLog.debug(LABEL_LOG, "%{public}s", "initCache,cache installed[" + httpCacheDir + "]"); 
  •     } catch (IOException e) {         HiLog.error(LABEL_LOG, "%{public}s", "initCache IOException"); 
  •     } } 
  •  b.保存缓存,将缓存写入文件系统 flush

     
  • private void flushCache(Component component) {     HiLog.debug(LABEL_LOG, "%{public}s", "flushCache"); 
  •     try {         //获取缓存对象 
  •         HttpResponseCache cache = HttpResponseCache.getInstalled();         HiLog.debug(LABEL_LOG, "%{public}s", "cache:"+cache); 
  •         if (cache != null) {             try { 
  •                 //将缓存写入文件系统,如果cache is closed 会报错 //java.lang.IllegalStateException: cache is closed                 cache.flush(); 
  •                 getUITaskDispatcher().syncDispatch(() -> {                     //图片加载时间,测试缓存和不缓存的差别 
  •                     duration.setText("cache flush success");                 }); 
  •                 HiLog.debug(LABEL_LOG, "%{public}s", "cache flush");             } catch (IOException e) { 
  •                 HiLog.error(LABEL_LOG, "%{public}s", "onStop IOException");             } 
  •         }     } catch (IllegalStateException e) { 
  •         e.printStackTrace();     } 
  • c.禁用缓存并删除其中的数据delete

     
  • private void deleteCache(Component component) {     HiLog.debug(LABEL_LOG, "%{public}s", "deleteCache"); 
  •     //获取缓存对象     HttpResponseCache cache = HttpResponseCache.getInstalled(); 
  •     HiLog.debug(LABEL_LOG, "%{public}s", "cache:"+cache);     if (cache != null) { 
  •         try {             //禁用缓存并删除其中的数据。 
  •             cache.delete();             image.setPixelMap(null); 
  •             HiLog.debug(LABEL_LOG, "%{public}s", "cache delete");         } catch (IOException e) { 
  •             HiLog.error(LABEL_LOG, "%{public}s", "onStop IOException");         } 
  •      } 
  • }  
  •  private void startRequest(Component component) { 
  •     HiLog.debug(LABEL_LOG, "%{public}s", "startRequest");     ThreadPoolUtil.submit(() -> { 
  •         try {             long startTime=System.currentTimeMillis(); 
  •             HiLog.debug(LABEL_LOG, "%{public}s", "startTime:"+startTime);             //请求URL 
  •             URL url = new URL(inputText.getText());             URLConnection urlConnection = url.openConnection(); 
  •             HiLog.debug(LABEL_LOG, "%{public}s", "openConnection");             //判断连接类型 
  •             if (urlConnection instanceof HttpURLConnection) {                 HiLog.debug(LABEL_LOG, "%{public}s", "urlConnection"); 
  •                 HttpURLConnection connection = (HttpURLConnection) urlConnection;                 HiLog.debug(LABEL_LOG, "%{public}s", "connect:"+connection); 
  •                 //连接                 connection.connect(); 
  •                 HiLog.debug(LABEL_LOG, "%{public}s", "connected");                 //连接结果 
  •                 if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {                     HiLog.debug(LABEL_LOG, "%{public}s", "HTTP_OK"); 
  •                     //描述图像数据源选项,例如包括表示为 image/png 的图像格式。                     ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); 
  •                     ImageSource imageSource = ImageSource.create(connection.getInputStream(), srcOpts);                     //以像素矩阵的形式提供图像。 
  •                     PixelMap pixelMap = imageSource.createPixelmap(null);                     HiLog.debug(LABEL_LOG, "%{public}s", "pixelMap:"+pixelMap); 
  •                     //专有线程同步设置图片显示                     getUITaskDispatcher().syncDispatch(() -> { 
  •                         image.setPixelMap(pixelMap);                         //图片加载时间,测试缓存和不缓存的差别 
  •                         duration.setText(String.valueOf(System.currentTimeMillis()-startTime)+" ms");                     }); 
  •                     HiLog.debug(LABEL_LOG, "%{public}s", "setPixelMap");                     HiLog.debug(LABEL_LOG, "%{public}s", "endTime:"+ (System.currentTimeMillis()-startTime)); 
  •                 }                 HiLog.debug(LABEL_LOG, "%{public}s", "finish"); 
  •                 //关闭连接                 connection.disconnect(); 
  •             }         } catch (Exception e) { 
  •             HiLog.error(LABEL_LOG, "%{public}s", "initCache Exception"+e);             getUITaskDispatcher().syncDispatch(() -> { 
  •                 //图片加载时间,测试缓存和不缓存的差别                 duration.setText("cache is closed, please open cache"); 
  •             });         } 
  •     }); } 
  • 5.总结说明

    (1)两种打开网络连接的方式

    URLConnection urlConnection = url.openConnection(); 
    //使用 netHandle打开URL连接,不使用代理 
  • URLConnection urlConnection = netHandle.openConnection(url, java.net.Proxy.NO_PROXY); 
  • (2)未开启缓存情况下,发送请求的时长在400-2000ms之间,开启后,需要点击两次发送请求,时长维持在90-200ms左右。

    (3)禁用并清除缓存delete/close后,在没有再次开启缓存前,无法发送请求。这个操作官方文档注释写的是 “结束时关闭缓存”。

    6.完整代码

    附件直接下载

    想了解更多内容,请访问:

    51CTO和华为官方合作共建的鸿蒙技术社区

    https://harmonyos.51cto.com



     

    转载请注明:文章转载自 www.mshxw.com
    本文地址:https://www.mshxw.com/it/823731.html
    我们一直用心在做
    关于我们 文章归档 网站地图 联系我们

    版权所有 (c)2021-2022 MSHXW.COM

    ICP备案号:晋ICP备2021003244-6号