本示例演示了如何使用網(wǎng)絡(luò)管理模塊相關(guān)接口,演示了以下功能:
-
功能 1:使用默認網(wǎng)絡(luò),打開連接,發(fā)送 HTTP 請求。
-
功能 2:統(tǒng)計指定 UID 的上行/下行流量。
-
功能 3:使用 Socket 方式實現(xiàn)不同設(shè)備間通信。此功能需要打開 WIFI,并且通信的設(shè)備連接相同的 WIFI 組成局域網(wǎng)。操作上,先啟動服務(wù)端,再啟動客戶端,然后從客戶端發(fā)送消息,查看服務(wù)端是否收到消息。
-
功能 4:HTTP 緩存的使用,創(chuàng)建緩存,供下一次請求使用,減少數(shù)據(jù)流量和加載時間。
注意,需要以下權(quán)限:
-
ohos.permission.GET_NETWORK_INFO:獲取網(wǎng)絡(luò)連接信息。
-
ohos.permission.SET_NETWORK_INFO:修改網(wǎng)絡(luò)連接狀態(tài)。
-
ohos.permission.INTERNET:允許程序打開網(wǎng)絡(luò)套接字,進行網(wǎng)絡(luò)連接。
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/connectivity-net-overview-0000000000029978
搭建環(huán)境
安裝 DevEco Studio,詳情請參考DevEco Studio 下載:
https://developer.harmonyos.com/cn/develop/deveco-studio
設(shè)置 DevEco Studio 開發(fā)環(huán)境,DevEco Studio 開發(fā)環(huán)境需要依賴于網(wǎng)絡(luò)環(huán)境,需要連接上網(wǎng)絡(luò)才能確保工具的正常使用。
可以根據(jù)如下兩種情況來配置開發(fā)環(huán)境:
-
如果可以直接訪問 Internet,只需進行下載 HarmonyOS SDK 操作。
- 如果網(wǎng)絡(luò)不能直接訪問 Internet,需要通過代理服務(wù)器才可以訪問,請參考配置開發(fā)環(huán)境。
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/environment_config-0000001052902427
下載源碼后,使用 DevEco Studio 打開項目,模擬器運行即可。真機運行需要將 config.json 中的 buddleName 修改為自己的,如果沒有請到 AGC 上進行配置。
參見《使用模擬器進行調(diào)試》:
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ide_debug_device-0000001053822404
代碼結(jié)構(gòu)
①代碼結(jié)構(gòu)
如下圖:

②相關(guān)文件介紹
核心類:
-
HttpURLConnection.java //支持 HTTP 特定功能的 URLConnection
-
URLConnection.java //URL 連接
-
URL.java //指向萬維網(wǎng)上“資源”的指針
-
NetStatusCallback.java //網(wǎng)絡(luò)狀態(tài)的回調(diào)類,出現(xiàn)可用網(wǎng)絡(luò)觸發(fā)onAvailable函數(shù)
-
DataFlowStatistics.java //該類提供查詢指定蜂窩網(wǎng)絡(luò)、應(yīng)用和網(wǎng)卡的整體流量統(tǒng)計和流量統(tǒng)計的接口
-
DatagramSocket.java //此類表示用于發(fā)送和接收數(shù)據(jù)報包的套接字。
-
DatagramPacket.java //數(shù)據(jù)報包
-
WifiDevice.java //該類提供 Wi-Fi 管理接口
-
NetManager.java //提供接口來管理和使用數(shù)據(jù)網(wǎng)絡(luò)
-
NetHandle.java //數(shù)據(jù)網(wǎng)絡(luò)
-
InetAddress.java //網(wǎng)絡(luò) IP 地址
-
HttpResponseCache.java //該類緩存 HTTP 和 HTTPS 響應(yīng)以供重用
自定義的類:
-
ThreadPoolUtil.java //線程池工具類
-
MainAbilitySlice.java //主頁面
-
NetRequestSlice.java //網(wǎng)絡(luò)請求&流量統(tǒng)計 功能頁
-
SocketClientSlice.java //Socket 客戶端
-
SocketServerSlice.java //Socket 服務(wù)端
-
HttpCacheSlice.java //HTTP 緩存功能頁
頁面布局:
-
http_cache_slice.xml //HTTP 緩存示例頁
-
net_request.slice.xml //HTTP 請求頁面
-
socket_client_slice.xml //Socket 通信客戶端頁
-
socket_server_slice.xml //Socket 通信服務(wù)端頁
-
main_ability_slice.xml //主頁面
實例講解
①界面布局
如下圖:



②后臺代碼
NetRequestSlice.java 網(wǎng)絡(luò)請求&流量統(tǒng)計功能
a.初始化網(wǎng)絡(luò)管理對象 NetManager。
//初始化網(wǎng)絡(luò)管理對象
netManager=NetManager.getInstance(null);
b.通過線程池獲取一個新線程處理進行連接請求,獲取默認數(shù)據(jù)網(wǎng)絡(luò)的時候需要 ohos.permission.GET_NETWORK_INFO 權(quán)限。
//用線程池的取一個新線程處理
ThreadPoolUtil.submit(()->{
HiLog.debug(LABEL_LOG,"%{public}s","ThreadPoolUtilsubmit");
//獲取默認的數(shù)據(jù)網(wǎng)絡(luò),wifi和流量都關(guān)閉時,netId==0,其它時netId=390/391,musthavetheohos.permission.GET_NETWORK_INFOpermission
NetHandlenetHandle=netManager.getDefaultNet();
//接收默認數(shù)據(jù)網(wǎng)絡(luò)的狀態(tài)更改的回調(diào)
netManager.addDefaultNetStatusCallback(callback);
//netManager.setAppNet(netHandle);
//支持 HTTP 特定功能的 URLConnection。
HttpURLConnectionconnection=null;
//輸出流
try(ByteArrayOutputStreamoutputStream=newByteArrayOutputStream()){
//請求的URL
StringurlString=inputText.getText();
URLurl=newURL(urlString);
//使用netHandle打開URL連接,不使用代理
URLConnectionurlConnection=netHandle.openConnection(url,java.net.Proxy.NO_PROXY);
HiLog.debug(LABEL_LOG,"%{public}s","netHandleopenConnection");
//強轉(zhuǎn)換類型
if(urlConnectioninstanceofHttpURLConnection){
connection=(HttpURLConnection)urlConnection;
}
//請求類型
connection.setRequestMethod("GET");
//連接
connection.connect();
//流量統(tǒng)計
trafficDataStatistics(false);
try(InputStreaminputStream=urlConnection.getInputStream()){
byte[]cache=newbyte[2*1024];
intlen=inputStream.read(cache);
while(len!=-1){
//
outputStream.write(cache,0,len);
len=inputStream.read(cache);
}
}catch(IOExceptione){
HiLog.error(LABEL_LOG,"%{public}s","netRequestinnerIOException");
}
//返回結(jié)果
Stringresult=newString(outputStream.toByteArray());
//UI顯示
getUITaskDispatcher().asyncDispatch(()->outText.setText(result));
//統(tǒng)計完畢
trafficDataStatistics(true);
}catch(IOExceptione){
HiLog.error(LABEL_LOG,"%{public}s","netRequestIOException");
}
});
c.按照應(yīng)用 ID,進行數(shù)據(jù)流量統(tǒng)計,在發(fā)送請求前獲取一次,在請求完成后獲取一次。
gitee 代碼中這個地方有一處筆誤,tx 代表上行流量,rx 代表下行流量才對。
詳情見官方文檔說明《流量統(tǒng)計》:
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/connectivity-net-traffic-0000000000045998
/**
*按照應(yīng)用ID,進行數(shù)據(jù)流量統(tǒng)計
*
*@paramisStart
*/
privatevoidtrafficDataStatistics(booleanisStart){
intuid=0;
try{
//根據(jù)給定的包名稱和用戶 ID 獲取應(yīng)用程序 UID。
uid=getBundleManager().getUidByBundleName(getBundleName(),0);
}catch(RemoteExceptione){
HiLog.error(LABEL_LOG,"%{public}s","trafficDataStatisticsRemoteException");
}
if(isStart){
//獲取指定UID的下行流量。
rx=DataFlowStatistics.getUidRxBytes(uid);
//獲取指定UID的上行流量。
tx=DataFlowStatistics.getUidTxBytes(uid);
}else{
rx=DataFlowStatistics.getUidRxBytes(uid)-rx;
tx=DataFlowStatistics.getUidTxBytes(uid)-tx;
//設(shè)置UI顯示
getUITaskDispatcher().asyncDispatch(()->statisticsText.setText(
"TrafficDataStatistics:"+System.lineSeparator()
+"Receivetraffic:"+rx+System.lineSeparator()
+"Senttraffic:"+tx));
}
}
}
SocketClientSlice.java/SocketServerSlice.java Socket 客戶端/服務(wù)端
實現(xiàn) Socket 通信,是要客戶端和服務(wù)端的,服務(wù)端在指定網(wǎng)卡上監(jiān)聽指定端口,客戶端向指定 IP 指定端口發(fā)送數(shù)據(jù),實現(xiàn)通信。
a.Socket 服務(wù)端開啟監(jiān)聽,等待接收數(shù)據(jù)。
//監(jiān)聽端口
privatestaticfinalintPORT=8888;
/**
*啟動socket服務(wù)監(jiān)聽
*
*@paramcomponent
*/
privatevoidstartServer(Componentcomponent){
HiLog.debug(LABEL_LOG,"startServer");
//線程池獲取新線程處理
ThreadPoolUtil.submit(()->{
//在指定端口開啟監(jiān)聽
try(DatagramSocketsocket=newDatagramSocket(PORT)){
//數(shù)據(jù)報包
DatagramPacketpacket=newDatagramPacket(newbyte[255],255);
//死循環(huán)接收數(shù)據(jù)
while(true){
//接收數(shù)據(jù)
socket.receive(packet);
//通過專有線程同步設(shè)置要顯示接收到的數(shù)據(jù)
getUITaskDispatcher().syncDispatch(()->outText.setText(
"Receiveamessagefrom:"+packet.getAddress().getHostAddress()
+System.lineSeparator()+"onport"+packet.getPort()
+System.lineSeparator()+"message:"+newString(
packet.getData()).substring(0,packet.getLength())
));
packet.setLength(255);
//延遲一下,留出處理數(shù)據(jù)的時間
Thread.sleep(1000);
}
}catch(IOException|InterruptedExceptione){
e.printStackTrace();
HiLog.error(LABEL_LOG,"%{public}s","StartServerIOException|InterruptedException"+e);
}
});
}
/**
*獲取服務(wù)器端IP地址,顯示給客戶端發(fā)送消息使用
*
*@return
*/
privateStringgetLocationIpAddress(){
HiLog.debug(LABEL_LOG,"getLocationIpAddress");
//提供接口來管理 Wi-Fi。
WifiDevicewifiDevice=WifiDevice.getInstance(this);
HiLog.debug(LABEL_LOG,"wifiDevice:"+wifiDevice);
//WifiLinkedInfo提供有關(guān) Wi-Fi 連接的信息。
OptionallinkedInfo=wifiDevice.getLinkedInfo();
HiLog.debug(LABEL_LOG,"linkedInfo:"+linkedInfo);
//獲取IP地址
intip=linkedInfo.get().getIpAddress();
HiLog.debug(LABEL_LOG,"ip:"+ip);
return(ip&0xFF)+"."+((ip>>8)&0xFF)+"."+((ip>>16)&0xFF)+"."+(ip>>24&0xFF);
}
b.Socket 客戶端發(fā)送數(shù)據(jù),等待接收數(shù)據(jù)。
初始化 NetManager 對象→new 一個 DatagramSocket→獲取當(dāng)前數(shù)據(jù)網(wǎng)絡(luò) NetHandle→獲取服務(wù)端的 IP 地址對象 InetAddress→將DatagramSocket 綁定到 NetHandle→new 一個數(shù)據(jù)報包 DatagramPacket→發(fā)送數(shù)據(jù)。
//通信端口
privatestaticfinalintPORT=8888;
/**
*發(fā)送網(wǎng)絡(luò)請求
*@paramcomponent
*/
privatevoidnetRequest(Componentcomponent){
HiLog.debug(LABEL_LOG,"netRequest");
//啟動新線程
ThreadPoolUtil.submit(()->{
//初始化網(wǎng)絡(luò)管理對象
NetManagernetManager=NetManager.getInstance(null);
//檢查默認數(shù)據(jù)網(wǎng)絡(luò)是否已激活。
if(!netManager.hasDefaultNet()){
return;
}
//new套接字
try(DatagramSocketsocket=newDatagramSocket()){
//獲取當(dāng)前數(shù)據(jù)網(wǎng)絡(luò)
NetHandlenetHandle=netManager.getDefaultNet();
//獲取服務(wù)端的IP地址
InetAddressaddress=netHandle.getByName(inputText.getText());
//將套接字綁定到當(dāng)前網(wǎng)絡(luò)
netHandle.bindSocket(socket);
byte[]buffer="I'mfromClient".getBytes();
//數(shù)據(jù)包
DatagramPacketrequest=newDatagramPacket(buffer,buffer.length,address,PORT);
//發(fā)送數(shù)據(jù)
socket.send(request);
HiLog.debug(LABEL_LOG,"sendsocket");
}catch(IOExceptione){
e.printStackTrace();
HiLog.error(LABEL_LOG,"%{public}s","netRequestIOException"+e);
}
});
}
HttpCacheSlice.java HTTP 緩存功能
應(yīng)用重復(fù)打開一個相同網(wǎng)頁時,可以優(yōu)先從緩存文件里讀取內(nèi)容,從而減少數(shù)據(jù)流量,降低設(shè)備功耗,提升應(yīng)用性能。問:如何設(shè)置優(yōu)先從緩存文件里讀取內(nèi)容?答:不用額外設(shè)置,自動的~~設(shè)置緩存,需要考慮緩存位置和緩存大小。
a.初始化緩存 install。
/**
*開啟緩存
*開啟后自動緩存數(shù)據(jù),不需要手動處理
*/
privatevoidinitCache(Componentcomponent){
//默認的緩存目錄
FilehttpCacheDir=newFile(this.getCacheDir(),"http");
//緩存大小
longhttpCacheSize=10*1024*1024;
try{
//配置緩存目錄及最大緩存空間
HttpResponseCache.install(httpCacheDir,httpCacheSize);
HiLog.debug(LABEL_LOG,"%{public}s","initCache,cacheinstalled["+httpCacheDir+"]");
}catch(IOExceptione){
HiLog.error(LABEL_LOG,"%{public}s","initCacheIOException");
}
}
b.保存緩存,將緩存寫入文件系統(tǒng) flush。
/**
*將緩存寫入文件系統(tǒng),防止緩存丟失
*/
privatevoidflushCache(Componentcomponent){
HiLog.debug(LABEL_LOG,"%{public}s","flushCache");
try{
//獲取緩存對象
HttpResponseCachecache=HttpResponseCache.getInstalled();
HiLog.debug(LABEL_LOG,"%{public}s","cache:"+cache);
if(cache!=null){
try{
//將緩存寫入文件系統(tǒng),如果cacheisclosed會報錯//java.lang.IllegalStateException:cacheisclosed
cache.flush();
getUITaskDispatcher().syncDispatch(()->{
//圖片加載時間,測試緩存和不緩存的差別
duration.setText("cacheflushsuccess");
});
HiLog.debug(LABEL_LOG,"%{public}s","cacheflush");
}catch(IOExceptione){
HiLog.error(LABEL_LOG,"%{public}s","onStopIOException");
}
}
}catch(IllegalStateExceptione){
e.printStackTrace();
}
}
c.禁用緩存并刪除其中的數(shù)據(jù) delete。
/**
*禁用緩存并刪除其中的數(shù)據(jù)
*/
privatevoiddeleteCache(Componentcomponent){
HiLog.debug(LABEL_LOG,"%{public}s","deleteCache");
//獲取緩存對象
HttpResponseCachecache=HttpResponseCache.getInstalled();
HiLog.debug(LABEL_LOG,"%{public}s","cache:"+cache);
if(cache!=null){
try{
//禁用緩存并刪除其中的數(shù)據(jù)。
cache.delete();
image.setPixelMap(null);
HiLog.debug(LABEL_LOG,"%{public}s","cachedelete");
}catch(IOExceptione){
HiLog.error(LABEL_LOG,"%{public}s","onStopIOException");
}
}
}
/**
*測試請求
*
*@paramcomponent
*/
privatevoidstartRequest(Componentcomponent){
HiLog.debug(LABEL_LOG,"%{public}s","startRequest");
ThreadPoolUtil.submit(()->{
try{
longstartTime=System.currentTimeMillis();
HiLog.debug(LABEL_LOG,"%{public}s","startTime:"+startTime);
//請求URL
URLurl=newURL(inputText.getText());
URLConnectionurlConnection=url.openConnection();
HiLog.debug(LABEL_LOG,"%{public}s","openConnection");
//判斷連接類型
if(urlConnectioninstanceofHttpURLConnection){
HiLog.debug(LABEL_LOG,"%{public}s","urlConnection");
HttpURLConnectionconnection=(HttpURLConnection)urlConnection;
HiLog.debug(LABEL_LOG,"%{public}s","connect:"+connection);
//連接
connection.connect();
HiLog.debug(LABEL_LOG,"%{public}s","connected");
//連接結(jié)果
if(connection.getResponseCode()==HttpURLConnection.HTTP_OK){
HiLog.debug(LABEL_LOG,"%{public}s","HTTP_OK");
//描述圖像數(shù)據(jù)源選項,例如包括表示為 image/png 的圖像格式。
ImageSource.SourceOptionssrcOpts=newImageSource.SourceOptions();
ImageSourceimageSource=ImageSource.create(connection.getInputStream(),srcOpts);
//以像素矩陣的形式提供圖像。
PixelMappixelMap=imageSource.createPixelmap(null);
HiLog.debug(LABEL_LOG,"%{public}s","pixelMap:"+pixelMap);
//專有線程同步設(shè)置圖片顯示
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");
//關(guān)閉連接
connection.disconnect();
}
}catch(Exceptione){
HiLog.error(LABEL_LOG,"%{public}s","initCacheException"+e);
getUITaskDispatcher().syncDispatch(()->{
//圖片加載時間,測試緩存和不緩存的差別
duration.setText("cacheisclosed,pleaseopencache");
});
}
});
}
總結(jié)說明
①兩種打開網(wǎng)絡(luò)連接的方式:
URLConnectionurlConnection=url.openConnection();
//使用netHandle打開URL連接,不使用代理
URLConnectionurlConnection=netHandle.openConnection(url,java.net.Proxy.NO_PROXY);
②未開啟緩存情況下,發(fā)送請求的時長在 400-2000ms 之間,開啟后,需要點擊兩次發(fā)送請求,時長維持在 90-200ms 左右。
③禁用并清除緩存 delete/close 后,在沒有再次開啟緩存前,無法發(fā)送請求。這個操作官方文檔注釋寫的是 “結(jié)束時關(guān)閉緩存”。
完整代碼
附件直接下載:
https://harmonyos.51cto.com/resource/1270
-
網(wǎng)絡(luò)管理
+關(guān)注
關(guān)注
0文章
127瀏覽量
29350 -
HTTP
+關(guān)注
關(guān)注
0文章
537瀏覽量
35382 -
數(shù)據(jù)包
+關(guān)注
關(guān)注
0文章
270瀏覽量
25600 -
代碼
+關(guān)注
關(guān)注
30文章
4968瀏覽量
73990 -
鴻蒙系統(tǒng)
+關(guān)注
關(guān)注
183文章
2642瀏覽量
69859
原文標題:鴻蒙的網(wǎng)絡(luò)管理功能,十分強悍!
文章出處:【微信號:gh_834c4b3d87fe,微信公眾號:OpenHarmony技術(shù)社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
藝開放平臺鴻蒙智能體版本管理
以龍企招為例,淺談鴻蒙應(yīng)用開發(fā)者激勵計劃 2025 參與心得
想體驗鴻蒙生態(tài),該怎么獲取鴻蒙開發(fā)板?有哪些途徑?
淘寶多規(guī)格SKU管理接口
管理型 vs 非管理型,工業(yè)網(wǎng)絡(luò)如何選擇以太網(wǎng)交換機?
鴻蒙的網(wǎng)絡(luò)管理功能你們知道有多厲害嗎
評論