-
功能 1:使用默認網絡,打開連接,發送 HTTP 請求。
-
功能 2:統計指定 UID 的上行/下行流量。
-
功能 3:使用 Socket 方式實現不同設備間通信。此功能需要打開 WIFI,并且通信的設備連接相同的 WIFI 組成局域網。操作上,先啟動服務端,再啟動客戶端,然后從客戶端發送消息,查看服務端是否收到消息。
-
功能 4:HTTP 緩存的使用,創建緩存,供下一次請求使用,減少數據流量和加載時間。
注意,需要以下權限:
-
ohos.permission.SET_NETWORK_INFO:修改網絡連接狀態。
-
ohos.permission.INTERNET:允許程序打開網絡套接字,進行網絡連接。
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/connectivity-net-overview-0000000000029978
搭建環境
安裝 DevEco Studio,詳情請參考DevEco Studio 下載:
https://developer.harmonyos.com/cn/develop/deveco-studio
設置 DevEco Studio 開發環境,DevEco Studio 開發環境需要依賴于網絡環境,需要連接上網絡才能確保工具的正常使用。
可以根據如下兩種情況來配置開發環境:
-
如果可以直接訪問 Internet,只需進行下載 HarmonyOS SDK 操作。
- 如果網絡不能直接訪問 Internet,需要通過代理服務器才可以訪問,請參考配置開發環境。
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/environment_config-0000001052902427
下載源碼后,使用 DevEco Studio 打開項目,模擬器運行即可。真機運行需要將 config.json 中的 buddleName 修改為自己的,如果沒有請到 AGC 上進行配置。
參見《使用模擬器進行調試》:
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ide_debug_device-0000001053822404
代碼結構
①代碼結構
如下圖:
②相關文件介紹
核心類:
-
HttpURLConnection.java //支持 HTTP 特定功能的 URLConnection
-
URLConnection.java //URL 連接
-
URL.java //指向萬維網上“資源”的指針
-
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 //主頁面
實例講解
①界面布局
如下圖:
②后臺代碼
NetRequestSlice.java 網絡請求&流量統計功能
a.初始化網絡管理對象 NetManager。
//初始化網絡管理對象
netManager=NetManager.getInstance(null);
b.通過線程池獲取一個新線程處理進行連接請求,獲取默認數據網絡的時候需要 ohos.permission.GET_NETWORK_INFO 權限。
//用線程池的取一個新線程處理
ThreadPoolUtil.submit(()->{
HiLog.debug(LABEL_LOG,"%{public}s","ThreadPoolUtilsubmit");
//獲取默認的數據網絡,wifi和流量都關閉時,netId==0,其它時netId=390/391,musthavetheohos.permission.GET_NETWORK_INFOpermission
NetHandlenetHandle=netManager.getDefaultNet();
//接收默認數據網絡的狀態更改的回調
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");
//強轉換類型
if(urlConnectioninstanceofHttpURLConnection){
connection=(HttpURLConnection)urlConnection;
}
//請求類型
connection.setRequestMethod("GET");
//連接
connection.connect();
//流量統計
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");
}
//返回結果
Stringresult=newString(outputStream.toByteArray());
//UI顯示
getUITaskDispatcher().asyncDispatch(()->outText.setText(result));
//統計完畢
trafficDataStatistics(true);
}catch(IOExceptione){
HiLog.error(LABEL_LOG,"%{public}s","netRequestIOException");
}
});
c.按照應用 ID,進行數據流量統計,在發送請求前獲取一次,在請求完成后獲取一次。
gitee 代碼中這個地方有一處筆誤,tx 代表上行流量,rx 代表下行流量才對。
詳情見官方文檔說明《流量統計》:
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/connectivity-net-traffic-0000000000045998
/**
*按照應用ID,進行數據流量統計
*
*@paramisStart
*/
privatevoidtrafficDataStatistics(booleanisStart){
intuid=0;
try{
//根據給定的包名稱和用戶 ID 獲取應用程序 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;
//設置UI顯示
getUITaskDispatcher().asyncDispatch(()->statisticsText.setText(
"TrafficDataStatistics:"+System.lineSeparator()
+"Receivetraffic:"+rx+System.lineSeparator()
+"Senttraffic:"+tx));
}
}
}
SocketClientSlice.java/SocketServerSlice.java Socket 客戶端/服務端
實現 Socket 通信,是要客戶端和服務端的,服務端在指定網卡上監聽指定端口,客戶端向指定 IP 指定端口發送數據,實現通信。
a.Socket 服務端開啟監聽,等待接收數據。
//監聽端口
privatestaticfinalintPORT=8888;
/**
*啟動socket服務監聽
*
*@paramcomponent
*/
privatevoidstartServer(Componentcomponent){
HiLog.debug(LABEL_LOG,"startServer");
//線程池獲取新線程處理
ThreadPoolUtil.submit(()->{
//在指定端口開啟監聽
try(DatagramSocketsocket=newDatagramSocket(PORT)){
//數據報包
DatagramPacketpacket=newDatagramPacket(newbyte[255],255);
//死循環接收數據
while(true){
//接收數據
socket.receive(packet);
//通過專有線程同步設置要顯示接收到的數據
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);
//延遲一下,留出處理數據的時間
Thread.sleep(1000);
}
}catch(IOException|InterruptedExceptione){
e.printStackTrace();
HiLog.error(LABEL_LOG,"%{public}s","StartServerIOException|InterruptedException"+e);
}
});
}
/**
*獲取服務器端IP地址,顯示給客戶端發送消息使用
*
*@return
*/
privateStringgetLocationIpAddress(){
HiLog.debug(LABEL_LOG,"getLocationIpAddress");
//提供接口來管理 Wi-Fi。
WifiDevicewifiDevice=WifiDevice.getInstance(this);
HiLog.debug(LABEL_LOG,"wifiDevice:"+wifiDevice);
//WifiLinkedInfo提供有關 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 客戶端發送數據,等待接收數據。
初始化 NetManager 對象→new 一個 DatagramSocket→獲取當前數據網絡 NetHandle→獲取服務端的 IP 地址對象 InetAddress→將DatagramSocket 綁定到 NetHandle→new 一個數據報包 DatagramPacket→發送數據。
//通信端口
privatestaticfinalintPORT=8888;
/**
*發送網絡請求
*@paramcomponent
*/
privatevoidnetRequest(Componentcomponent){
HiLog.debug(LABEL_LOG,"netRequest");
//啟動新線程
ThreadPoolUtil.submit(()->{
//初始化網絡管理對象
NetManagernetManager=NetManager.getInstance(null);
//檢查默認數據網絡是否已激活。
if(!netManager.hasDefaultNet()){
return;
}
//new套接字
try(DatagramSocketsocket=newDatagramSocket()){
//獲取當前數據網絡
NetHandlenetHandle=netManager.getDefaultNet();
//獲取服務端的IP地址
InetAddressaddress=netHandle.getByName(inputText.getText());
//將套接字綁定到當前網絡
netHandle.bindSocket(socket);
byte[]buffer="I'mfromClient".getBytes();
//數據包
DatagramPacketrequest=newDatagramPacket(buffer,buffer.length,address,PORT);
//發送數據
socket.send(request);
HiLog.debug(LABEL_LOG,"sendsocket");
}catch(IOExceptione){
e.printStackTrace();
HiLog.error(LABEL_LOG,"%{public}s","netRequestIOException"+e);
}
});
}
HttpCacheSlice.java HTTP 緩存功能
應用重復打開一個相同網頁時,可以優先從緩存文件里讀取內容,從而減少數據流量,降低設備功耗,提升應用性能。問:如何設置優先從緩存文件里讀取內容?答:不用額外設置,自動的~~設置緩存,需要考慮緩存位置和緩存大小。
a.初始化緩存 install。
/**
*開啟緩存
*開啟后自動緩存數據,不需要手動處理
*/
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.保存緩存,將緩存寫入文件系統 flush。
/**
*將緩存寫入文件系統,防止緩存丟失
*/
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{
//將緩存寫入文件系統,如果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.禁用緩存并刪除其中的數據 delete。
/**
*禁用緩存并刪除其中的數據
*/
privatevoiddeleteCache(Componentcomponent){
HiLog.debug(LABEL_LOG,"%{public}s","deleteCache");
//獲取緩存對象
HttpResponseCachecache=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","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");
//連接結果
if(connection.getResponseCode()==HttpURLConnection.HTTP_OK){
HiLog.debug(LABEL_LOG,"%{public}s","HTTP_OK");
//描述圖像數據源選項,例如包括表示為 image/png 的圖像格式。
ImageSource.SourceOptionssrcOpts=newImageSource.SourceOptions();
ImageSourceimageSource=ImageSource.create(connection.getInputStream(),srcOpts);
//以像素矩陣的形式提供圖像。
PixelMappixelMap=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(Exceptione){
HiLog.error(LABEL_LOG,"%{public}s","initCacheException"+e);
getUITaskDispatcher().syncDispatch(()->{
//圖片加載時間,測試緩存和不緩存的差別
duration.setText("cacheisclosed,pleaseopencache");
});
}
});
}
總結說明
①兩種打開網絡連接的方式:
URLConnectionurlConnection=url.openConnection();
//使用netHandle打開URL連接,不使用代理
URLConnectionurlConnection=netHandle.openConnection(url,java.net.Proxy.NO_PROXY);
②未開啟緩存情況下,發送請求的時長在 400-2000ms 之間,開啟后,需要點擊兩次發送請求,時長維持在 90-200ms 左右。
③禁用并清除緩存 delete/close 后,在沒有再次開啟緩存前,無法發送請求。這個操作官方文檔注釋寫的是 “結束時關閉緩存”。
完整代碼
附件直接下載:
https://harmonyos.51cto.com/resource/1270
-
網絡管理
+關注
關注
0文章
120瀏覽量
27670 -
HTTP
+關注
關注
0文章
504瀏覽量
31198 -
數據包
+關注
關注
0文章
260瀏覽量
24385 -
代碼
+關注
關注
30文章
4780瀏覽量
68539 -
鴻蒙系統
+關注
關注
183文章
2634瀏覽量
66308
原文標題:鴻蒙的網絡管理功能,十分強悍!
文章出處:【微信號:gh_834c4b3d87fe,微信公眾號:OpenHarmony技術社區】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論