本示例演示了如何使用網(wǎng)絡(luò)管理模塊相關(guān)接口,演示了以下功能:
-
功能 1:使用默認(rèn)網(wǎng)絡(luò),打開(kāi)連接,發(fā)送 HTTP 請(qǐng)求。
-
功能 2:統(tǒng)計(jì)指定 UID 的上行/下行流量。
-
功能 3:使用 Socket 方式實(shí)現(xiàn)不同設(shè)備間通信。此功能需要打開(kāi) WIFI,并且通信的設(shè)備連接相同的 WIFI 組成局域網(wǎng)。操作上,先啟動(dòng)服務(wù)端,再啟動(dòng)客戶(hù)端,然后從客戶(hù)端發(fā)送消息,查看服務(wù)端是否收到消息。
-
功能 4:HTTP 緩存的使用,創(chuàng)建緩存,供下一次請(qǐng)求使用,減少數(shù)據(jù)流量和加載時(shí)間。
注意,需要以下權(quán)限:
-
ohos.permission.GET_NETWORK_INFO:獲取網(wǎng)絡(luò)連接信息。
-
ohos.permission.SET_NETWORK_INFO:修改網(wǎng)絡(luò)連接狀態(tài)。
-
ohos.permission.INTERNET:允許程序打開(kāi)網(wǎng)絡(luò)套接字,進(jìn)行網(wǎng)絡(luò)連接。
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/connectivity-net-overview-0000000000029978
搭建環(huán)境
安裝 DevEco Studio,詳情請(qǐng)參考DevEco Studio 下載:
https://developer.harmonyos.com/cn/develop/deveco-studio
設(shè)置 DevEco Studio 開(kāi)發(fā)環(huán)境,DevEco Studio 開(kāi)發(fā)環(huán)境需要依賴(lài)于網(wǎng)絡(luò)環(huán)境,需要連接上網(wǎng)絡(luò)才能確保工具的正常使用。
可以根據(jù)如下兩種情況來(lái)配置開(kāi)發(fā)環(huán)境:
-
如果可以直接訪(fǎng)問(wèn) Internet,只需進(jìn)行下載 HarmonyOS SDK 操作。
- 如果網(wǎng)絡(luò)不能直接訪(fǎng)問(wèn) Internet,需要通過(guò)代理服務(wù)器才可以訪(fǎng)問(wèn),請(qǐng)參考配置開(kāi)發(fā)環(huán)境。
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/environment_config-0000001052902427
下載源碼后,使用 DevEco Studio 打開(kāi)項(xiàng)目,模擬器運(yùn)行即可。真機(jī)運(yùn)行需要將 config.json 中的 buddleName 修改為自己的,如果沒(méi)有請(qǐng)到 AGC 上進(jìn)行配置。
參見(jiàn)《使用模擬器進(jìn)行調(diào)試》:
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ide_debug_device-0000001053822404
代碼結(jié)構(gòu)
①代碼結(jié)構(gòu)
如下圖:
②相關(guān)文件介紹
核心類(lèi):
-
HttpURLConnection.java //支持 HTTP 特定功能的 URLConnection
-
URLConnection.java //URL 連接
-
URL.java //指向萬(wàn)維網(wǎng)上“資源”的指針
-
NetStatusCallback.java //網(wǎng)絡(luò)狀態(tài)的回調(diào)類(lèi),出現(xiàn)可用網(wǎng)絡(luò)觸發(fā)onAvailable函數(shù)
-
DataFlowStatistics.java //該類(lèi)提供查詢(xún)指定蜂窩網(wǎng)絡(luò)、應(yīng)用和網(wǎng)卡的整體流量統(tǒng)計(jì)和流量統(tǒng)計(jì)的接口
-
DatagramSocket.java //此類(lèi)表示用于發(fā)送和接收數(shù)據(jù)報(bào)包的套接字。
-
DatagramPacket.java //數(shù)據(jù)報(bào)包
-
WifiDevice.java //該類(lèi)提供 Wi-Fi 管理接口
-
NetManager.java //提供接口來(lái)管理和使用數(shù)據(jù)網(wǎng)絡(luò)
-
NetHandle.java //數(shù)據(jù)網(wǎng)絡(luò)
-
InetAddress.java //網(wǎng)絡(luò) IP 地址
-
HttpResponseCache.java //該類(lèi)緩存 HTTP 和 HTTPS 響應(yīng)以供重用
自定義的類(lèi):
-
ThreadPoolUtil.java //線(xiàn)程池工具類(lèi)
-
MainAbilitySlice.java //主頁(yè)面
-
NetRequestSlice.java //網(wǎng)絡(luò)請(qǐng)求&流量統(tǒng)計(jì) 功能頁(yè)
-
SocketClientSlice.java //Socket 客戶(hù)端
-
SocketServerSlice.java //Socket 服務(wù)端
-
HttpCacheSlice.java //HTTP 緩存功能頁(yè)
頁(yè)面布局:
-
http_cache_slice.xml //HTTP 緩存示例頁(yè)
-
net_request.slice.xml //HTTP 請(qǐng)求頁(yè)面
-
socket_client_slice.xml //Socket 通信客戶(hù)端頁(yè)
-
socket_server_slice.xml //Socket 通信服務(wù)端頁(yè)
-
main_ability_slice.xml //主頁(yè)面
實(shí)例講解
①界面布局
如下圖:
②后臺(tái)代碼
NetRequestSlice.java 網(wǎng)絡(luò)請(qǐng)求&流量統(tǒng)計(jì)功能
a.初始化網(wǎng)絡(luò)管理對(duì)象 NetManager。
//初始化網(wǎng)絡(luò)管理對(duì)象
netManager=NetManager.getInstance(null);
b.通過(guò)線(xiàn)程池獲取一個(gè)新線(xiàn)程處理進(jìn)行連接請(qǐng)求,獲取默認(rèn)數(shù)據(jù)網(wǎng)絡(luò)的時(shí)候需要 ohos.permission.GET_NETWORK_INFO 權(quán)限。
//用線(xiàn)程池的取一個(gè)新線(xiàn)程處理
ThreadPoolUtil.submit(()->{
HiLog.debug(LABEL_LOG,"%{public}s","ThreadPoolUtilsubmit");
//獲取默認(rèn)的數(shù)據(jù)網(wǎng)絡(luò),wifi和流量都關(guān)閉時(shí),netId==0,其它時(shí)netId=390/391,musthavetheohos.permission.GET_NETWORK_INFOpermission
NetHandlenetHandle=netManager.getDefaultNet();
//接收默認(rèn)數(shù)據(jù)網(wǎng)絡(luò)的狀態(tài)更改的回調(diào)
netManager.addDefaultNetStatusCallback(callback);
//netManager.setAppNet(netHandle);
//支持 HTTP 特定功能的 URLConnection。
HttpURLConnectionconnection=null;
//輸出流
try(ByteArrayOutputStreamoutputStream=newByteArrayOutputStream()){
//請(qǐng)求的URL
StringurlString=inputText.getText();
URLurl=newURL(urlString);
//使用netHandle打開(kāi)URL連接,不使用代理
URLConnectionurlConnection=netHandle.openConnection(url,java.net.Proxy.NO_PROXY);
HiLog.debug(LABEL_LOG,"%{public}s","netHandleopenConnection");
//強(qiáng)轉(zhuǎn)換類(lèi)型
if(urlConnectioninstanceofHttpURLConnection){
connection=(HttpURLConnection)urlConnection;
}
//請(qǐng)求類(lèi)型
connection.setRequestMethod("GET");
//連接
connection.connect();
//流量統(tǒng)計(jì)
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)計(jì)完畢
trafficDataStatistics(true);
}catch(IOExceptione){
HiLog.error(LABEL_LOG,"%{public}s","netRequestIOException");
}
});
c.按照應(yīng)用 ID,進(jìn)行數(shù)據(jù)流量統(tǒng)計(jì),在發(fā)送請(qǐng)求前獲取一次,在請(qǐng)求完成后獲取一次。
gitee 代碼中這個(gè)地方有一處筆誤,tx 代表上行流量,rx 代表下行流量才對(duì)。
詳情見(jiàn)官方文檔說(shuō)明《流量統(tǒng)計(jì)》:
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/connectivity-net-traffic-0000000000045998
/**
*按照應(yīng)用ID,進(jìn)行數(shù)據(jù)流量統(tǒng)計(jì)
*
*@paramisStart
*/
privatevoidtrafficDataStatistics(booleanisStart){
intuid=0;
try{
//根據(jù)給定的包名稱(chēng)和用戶(hù) 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 客戶(hù)端/服務(wù)端
實(shí)現(xiàn) Socket 通信,是要客戶(hù)端和服務(wù)端的,服務(wù)端在指定網(wǎng)卡上監(jiān)聽(tīng)指定端口,客戶(hù)端向指定 IP 指定端口發(fā)送數(shù)據(jù),實(shí)現(xiàn)通信。
a.Socket 服務(wù)端開(kāi)啟監(jiān)聽(tīng),等待接收數(shù)據(jù)。
//監(jiān)聽(tīng)端口
privatestaticfinalintPORT=8888;
/**
*啟動(dòng)socket服務(wù)監(jiān)聽(tīng)
*
*@paramcomponent
*/
privatevoidstartServer(Componentcomponent){
HiLog.debug(LABEL_LOG,"startServer");
//線(xiàn)程池獲取新線(xiàn)程處理
ThreadPoolUtil.submit(()->{
//在指定端口開(kāi)啟監(jiān)聽(tīng)
try(DatagramSocketsocket=newDatagramSocket(PORT)){
//數(shù)據(jù)報(bào)包
DatagramPacketpacket=newDatagramPacket(newbyte[255],255);
//死循環(huán)接收數(shù)據(jù)
while(true){
//接收數(shù)據(jù)
socket.receive(packet);
//通過(guò)專(zhuān)有線(xiàn)程同步設(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ù)的時(shí)間
Thread.sleep(1000);
}
}catch(IOException|InterruptedExceptione){
e.printStackTrace();
HiLog.error(LABEL_LOG,"%{public}s","StartServerIOException|InterruptedException"+e);
}
});
}
/**
*獲取服務(wù)器端IP地址,顯示給客戶(hù)端發(fā)送消息使用
*
*@return
*/
privateStringgetLocationIpAddress(){
HiLog.debug(LABEL_LOG,"getLocationIpAddress");
//提供接口來(lái)管理 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 客戶(hù)端發(fā)送數(shù)據(jù),等待接收數(shù)據(jù)。
初始化 NetManager 對(duì)象→new 一個(gè) DatagramSocket→獲取當(dāng)前數(shù)據(jù)網(wǎng)絡(luò) NetHandle→獲取服務(wù)端的 IP 地址對(duì)象 InetAddress→將DatagramSocket 綁定到 NetHandle→new 一個(gè)數(shù)據(jù)報(bào)包 DatagramPacket→發(fā)送數(shù)據(jù)。
//通信端口
privatestaticfinalintPORT=8888;
/**
*發(fā)送網(wǎng)絡(luò)請(qǐng)求
*@paramcomponent
*/
privatevoidnetRequest(Componentcomponent){
HiLog.debug(LABEL_LOG,"netRequest");
//啟動(dòng)新線(xiàn)程
ThreadPoolUtil.submit(()->{
//初始化網(wǎng)絡(luò)管理對(duì)象
NetManagernetManager=NetManager.getInstance(null);
//檢查默認(rèn)數(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ù)打開(kāi)一個(gè)相同網(wǎng)頁(yè)時(shí),可以?xún)?yōu)先從緩存文件里讀取內(nèi)容,從而減少數(shù)據(jù)流量,降低設(shè)備功耗,提升應(yīng)用性能。問(wèn):如何設(shè)置優(yōu)先從緩存文件里讀取內(nèi)容?答:不用額外設(shè)置,自動(dòng)的~~設(shè)置緩存,需要考慮緩存位置和緩存大小。
a.初始化緩存 install。
/**
*開(kāi)啟緩存
*開(kāi)啟后自動(dòng)緩存數(shù)據(jù),不需要手動(dòng)處理
*/
privatevoidinitCache(Componentcomponent){
//默認(rèn)的緩存目錄
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.保存緩存,將緩存寫(xiě)入文件系統(tǒng) flush。
/**
*將緩存寫(xiě)入文件系統(tǒng),防止緩存丟失
*/
privatevoidflushCache(Componentcomponent){
HiLog.debug(LABEL_LOG,"%{public}s","flushCache");
try{
//獲取緩存對(duì)象
HttpResponseCachecache=HttpResponseCache.getInstalled();
HiLog.debug(LABEL_LOG,"%{public}s","cache:"+cache);
if(cache!=null){
try{
//將緩存寫(xiě)入文件系統(tǒng),如果cacheisclosed會(huì)報(bào)錯(cuò)//java.lang.IllegalStateException:cacheisclosed
cache.flush();
getUITaskDispatcher().syncDispatch(()->{
//圖片加載時(shí)間,測(cè)試緩存和不緩存的差別
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");
//獲取緩存對(duì)象
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");
}
}
}
/**
*測(cè)試請(qǐng)求
*
*@paramcomponent
*/
privatevoidstartRequest(Componentcomponent){
HiLog.debug(LABEL_LOG,"%{public}s","startRequest");
ThreadPoolUtil.submit(()->{
try{
longstartTime=System.currentTimeMillis();
HiLog.debug(LABEL_LOG,"%{public}s","startTime:"+startTime);
//請(qǐng)求URL
URLurl=newURL(inputText.getText());
URLConnectionurlConnection=url.openConnection();
HiLog.debug(LABEL_LOG,"%{public}s","openConnection");
//判斷連接類(lèi)型
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ù)源選項(xiàng),例如包括表示為 image/png 的圖像格式。
ImageSource.SourceOptionssrcOpts=newImageSource.SourceOptions();
ImageSourceimageSource=ImageSource.create(connection.getInputStream(),srcOpts);
//以像素矩陣的形式提供圖像。
PixelMappixelMap=imageSource.createPixelmap(null);
HiLog.debug(LABEL_LOG,"%{public}s","pixelMap:"+pixelMap);
//專(zhuān)有線(xiàn)程同步設(shè)置圖片顯示
getUITaskDispatcher().syncDispatch(()->{
image.setPixelMap(pixelMap);
//圖片加載時(shí)間,測(cè)試緩存和不緩存的差別
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(()->{
//圖片加載時(shí)間,測(cè)試緩存和不緩存的差別
duration.setText("cacheisclosed,pleaseopencache");
});
}
});
}
總結(jié)說(shuō)明
①兩種打開(kāi)網(wǎng)絡(luò)連接的方式:
URLConnectionurlConnection=url.openConnection();
//使用netHandle打開(kāi)URL連接,不使用代理
URLConnectionurlConnection=netHandle.openConnection(url,java.net.Proxy.NO_PROXY);
②未開(kāi)啟緩存情況下,發(fā)送請(qǐng)求的時(shí)長(zhǎng)在 400-2000ms 之間,開(kāi)啟后,需要點(diǎn)擊兩次發(fā)送請(qǐng)求,時(shí)長(zhǎng)維持在 90-200ms 左右。
③禁用并清除緩存 delete/close 后,在沒(méi)有再次開(kāi)啟緩存前,無(wú)法發(fā)送請(qǐng)求。這個(gè)操作官方文檔注釋寫(xiě)的是 “結(jié)束時(shí)關(guān)閉緩存”。
完整代碼
附件直接下載:
https://harmonyos.51cto.com/resource/1270
-
網(wǎng)絡(luò)管理
+關(guān)注
關(guān)注
0文章
123瀏覽量
28049 -
HTTP
+關(guān)注
關(guān)注
0文章
522瀏覽量
32468 -
數(shù)據(jù)包
+關(guān)注
關(guān)注
0文章
269瀏覽量
24882 -
代碼
+關(guān)注
關(guān)注
30文章
4887瀏覽量
70266 -
鴻蒙系統(tǒng)
+關(guān)注
關(guān)注
183文章
2639瀏覽量
67719
原文標(biāo)題:鴻蒙的網(wǎng)絡(luò)管理功能,十分強(qiáng)悍!
文章出處:【微信號(hào):gh_834c4b3d87fe,微信公眾號(hào):OpenHarmony技術(shù)社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
設(shè)備綜合管理平臺(tái)有哪些功能特點(diǎn)
鴻蒙5開(kāi)發(fā)寶藏案例分享---自由流轉(zhuǎn)的拖拽多屏聯(lián)動(dòng)
數(shù)字化能源管理系統(tǒng)平臺(tái)有什么功能
DevEco Studio AI輔助開(kāi)發(fā)工具兩大升級(jí)功能 鴻蒙應(yīng)用開(kāi)發(fā)效率再提升
在線(xiàn)監(jiān)測(cè)管理系統(tǒng)的智能化功能詳解 多角色權(quán)限與多項(xiàng)目管理 多終端適配
開(kāi)源啦?。。』?b class='flag-5'>鴻蒙ArkTS封裝的圖表組件《McCharts》,大家快來(lái)一起共創(chuàng)
AIGC入門(mén)及鴻蒙入門(mén)
鴻蒙Flutter實(shí)戰(zhàn):14-現(xiàn)有Flutter 項(xiàng)目支持鴻蒙 II
ShiMeta鴻蒙多屏同步拼接解決方案

評(píng)論