1# 网络连接管理
2
3## 简介
4
5网络连接管理提供管理网络一些基础能力,包括WiFi/蜂窝/Ethernet等多网络连接优先级管理、网络质量评估、订阅默认/指定网络连接状态变化、查询网络连接信息、DNS解析等功能。
6
7> **说明:**
8> 为了保证应用的运行效率,大部分API调用都是异步的,对于异步调用的API均提供了callback和Promise两种方式,以下示例均采用promise函数,更多方式可以查阅[API参考](../reference/apis-network-kit/js-apis-net-connection.md)。
9
10## 基本概念
11
12- 网络生产者:数据网络的提供方,比如WiFi、蜂窝、Ethernet等。
13- 网络消费者:数据网络的使用方,比如应用或系统服务。
14- 网络探测:检测网络有效性,避免将网络从可用网络切换到不可用网络。内容包括绑定网络探测、DNS探测、HTTP探测及HTTPS探测。
15- 网络优选:处理多网络共存时选择最优网络。在网络状态、网络信息及评分发生变化时被触发。
16
17## 约束
18
19- 开发语言:JS
20- 本模块首批接口从API version 8开始支持。后续版本的新增接口,采用上角标单独标记接口的起始版本。
21
22## 场景介绍
23
24网络连接管理的典型场景有:
25
26- 接收指定网络的状态变化通知
27- 获取所有注册的网络
28- 根据数据网络查询网络的连接信息
29- 使用对应网络解析域名,获取所有IP
30
31以下分别介绍具体开发方式。
32
33## 接口说明
34
35完整的JS API说明以及实例代码请参考:[网络连接管理](../reference/apis-network-kit/js-apis-net-connection.md)。
36
37| 接口名 | 描述 |
38| ---- | ---- |
39| getDefaultNet(callback: AsyncCallback\<NetHandle>): void; |获取一个含有默认网络的netId的NetHandle对象,使用callback回调 |
40| <!--DelRow--> getGlobalHttpProxy(callback: AsyncCallback\<HttpProxy>): void;| 获取网络的全局代理设置,使用callback回调 |
41| <!--DelRow--> setGlobalHttpProxy(httpProxy: HttpProxy, callback: AsyncCallback\<void>): void;| 设置网络全局Http代理配置信息,使用callback回调 |
42| setAppHttpProxy(httpProxy: HttpProxy): void;| 设置网络应用级Http代理配置信息 |
43| getAppNet(callback: AsyncCallback\<NetHandle>): void;| 获取一个App绑定的包含了网络netId的NetHandle对象,使用callback回调 |
44| setAppNet(netHandle: NetHandle, callback: AsyncCallback\<void>): void;| 绑定App到指定网络,绑定后的App只能通过指定网络访问外网。使用callback回调 |
45| getDefaultNetSync(): NetHandle; |使用同步方法获取默认激活的数据网络。可以使用getNetCapabilities去获取网络的类型、拥有的能力等信息。|
46| hasDefaultNet(callback: AsyncCallback\<boolean>): void; |检查默认数据网络是否被激活,使用callback回调 |
47| getAllNets(callback: AsyncCallback\<Array\<NetHandle>>): void;| 获取所处于连接状态的网络的NetHandle对象列表,使用callback回调 |
48| getConnectionProperties(netHandle: NetHandle, callback: AsyncCallback\<ConnectionProperties>): void; |查询netHandle对应的网络的连接信息,使用callback回调 |
49| getNetCapabilities(netHandle: NetHandle, callback: AsyncCallback\<NetCapabilities>): void; |获取netHandle对应的网络的能力信息,使用callback回调 |
50| isDefaultNetMetered(callback: AsyncCallback\<boolean>): void; |检查当前网络上的数据流量使用是否被计量,使用callback方式作为异步方法 |
51| reportNetConnected(netHandle: NetHandle, callback: AsyncCallback\<void>): void;| 向网络管理报告网络处于可用状态,调用此接口说明应用程序认为网络的可用性(ohos.net.connection.NetCap.NET_CAPABILITY_VAILDATED)与网络管理不一致。使用callback回调 |
52| reportNetDisconnected(netHandle: NetHandle, callback: AsyncCallback\<void>): void;| 向网络管理报告网络处于不可用状态,调用此接口说明应用程序认为网络的可用性(ohos.net.connection.NetCap.NET_CAPABILITY_VAILDATED)与网络管理不一致。使用callback回调 |
53| getAddressesByName(host: string, callback: AsyncCallback\<Array\<NetAddress>>): void; |使用对应网络解析域名,获取所有IP,使用callback回调 |
54| <!--DelRow--> enableAirplaneMode(callback: AsyncCallback\<void>): void; | 设置网络为飞行模式,使用callback回调 |
55| <!--DelRow--> disableAirplaneMode(callback: AsyncCallback\<void>): void;| 关闭网络飞行模式,使用callback回调 |
56| createNetConnection(netSpecifier?: NetSpecifier, timeout?: number): NetConnection; | 返回一个NetConnection对象,netSpecifier指定关注的网络的各项特征,timeout是超时时间(单位是毫秒),netSpecifier是timeout的必要条件,两者都没有则表示关注默认网络 |
57| bindSocket(socketParam: TCPSocket \| UDPSocket, callback: AsyncCallback\<void>): void; | 将TCPSocket或UDPSockett绑定到当前网络,使用callback回调 |
58| getAddressesByName(host: string, callback: AsyncCallback\<Array\<NetAddress>>): void; |使用对应网络解析域名,获取所有IP,使用callback回调 |
59| getAddressByName(host: string, callback: AsyncCallback\<NetAddress>): void; |使用对应网络解析域名,获取一个IP,调用callbac |
60| on(type: 'netAvailable', callback: Callback\<NetHandle>): void;                   |订阅网络可用事件 |
61| on(type: 'netCapabilitiesChange', callback: Callback\<NetCapabilityInfo\>): void; |订阅网络能力变化事件 |
62| on(type: 'netConnectionPropertiesChange', callback: Callback\<{ netHandle: NetHandle, connectionProperties: ConnectionProperties }>): void; |订阅网络连接信息变化事件 |
63| on(type: 'netBlockStatusChange', callback: Callback<{ netHandle: NetHandle, blocked: boolean }>): void; |订阅网络阻塞状态事件,使用callback方式作为异步方法 |
64| on(type: 'netLost', callback: Callback\<NetHandle>): void; |订阅网络丢失事件 |
65| on(type: 'netUnavailable', callback: Callback\<void>): void; |订阅网络不可用事件 |
66| register(callback: AsyncCallback\<void>): void; |订阅指定网络状态变化的通知 |
67| unregister(callback: AsyncCallback\<void>): void; |取消订阅默认网络状态变化的通知 |
68
69## 接收指定网络的状态变化通知
70
711. 声明接口调用所需要的权限:ohos.permission.GET_NETWORK_INFO72此权限级别为normal,在申请权限前,请保证符合[权限使用的基本原则](../security/AccessToken/app-permission-mgmt-overview.md#权限使用的基本原则)。然后参考[访问控制-声明权限](../security/AccessToken/declare-permissions.md)声明对应权限。
73
741. 从@kit.NetworkKit中导入connection命名空间。
75
762. 调用createNetConnection方法,指定网络能力、网络类型和超时时间(可选,如不传入代表默认网络;创建不同于默认网络时可通过指定这些参数完成),创建一个NetConnection对象。
77
783. 调用该对象的on()方法,传入type和callback,订阅关心的事件。
79
804. 调用该对象的register()方法,订阅指定网络状态变化的通知。
81
825. 当网络可用时,会收到netAvailable事件的回调;当网络不可用时,会收到netUnavailable事件的回调。
83
846. 当不使用该网络时,可以调用该对象的unregister()方法,取消订阅。
85
86```ts
87// 引入包名
88import { connection } from '@kit.NetworkKit';
89import { BusinessError } from '@kit.BasicServicesKit';
90
91let netSpecifier: connection.NetSpecifier = {
92  netCapabilities: {
93    // 假设当前默认网络是WiFi,需要创建蜂窝网络连接,可指定网络类型为蜂窝网
94    bearerTypes: [connection.NetBearType.BEARER_CELLULAR],
95    // 指定网络能力为Internet
96    networkCap: [connection.NetCap.NET_CAPABILITY_INTERNET]
97  },
98};
99
100// 指定超时时间为10s(默认值为0)
101let timeout = 10 * 1000;
102
103// 创建NetConnection对象
104let conn = connection.createNetConnection(netSpecifier, timeout);
105
106// 订阅指定网络状态变化的通知
107conn.register((err: BusinessError, data: void) => {
108  console.log(JSON.stringify(err));
109});
110
111// 订阅事件,如果当前指定网络可用,通过on_netAvailable通知用户
112conn.on('netAvailable', ((data: connection.NetHandle) => {
113  console.log("net is available, netId is " + data.netId);
114}));
115
116// 订阅事件,如果当前指定网络不可用,通过on_netUnavailable通知用户
117conn.on('netUnavailable', ((data: void) => {
118  console.log("net is unavailable, data is " + JSON.stringify(data));
119}));
120
121// 当不使用该网络时,可以调用该对象的unregister()方法,取消订阅
122conn.unregister((err: BusinessError, data: void) => {
123});
124```
125
126## 监控默认网络变化并主动重建网络连接
127
128根据当前网络状态及网络质量情况,默认网络可能会发生变化,如:
1291. 在WiFi弱信号的情况下,默认网络可能会切换到蜂窝网络。
1302. 在蜂窝网络状态差的情况下,默认网络可能会切换到WiFi。
1313. 关闭WiFi后,默认网络可能会切换到蜂窝网络。
1324. 关闭蜂窝网络后,默认网络可能会切换到WiFi。
1335. 在WiFi弱信号的情况下,默认网络可能会切换到其他WiFi(存在跨网情况)。
1346. 在蜂窝网络状态差的情况下,默认网络可能会切换到其他蜂窝(存在跨网情况)。
135
136本节旨在介绍监控默认网络的变化后,应用报文能够快速迁移到新默认网络上,具体做法如下。
137
138### 监控默认网络变化
139
140```ts
141import { connection } from '@kit.NetworkKit';
142
143async function test() {
144  const netConnection = connection.createNetConnection();
145
146  /* 监听默认网络改变 */
147  netConnection.on('netAvailable', (data: connection.NetHandle) => {
148    console.log(JSON.stringify(data));
149  });
150}
151```
152
153### 默认网络变化后重新建立网络连接
154
155#### 原网络连接使用http模块建立网络连接
156
157如果您使用了http模块建立网络连接,由于该模块没有提供Close接口用于关闭Socket,在切换默认网络并建立新的网络连接后原有Socket不会立即关闭。因此请切换使用Remote Communication Kit建立网络连接。
158
159#### 原网络连接使用Remote Communication Kit建立网络连接
160
161```ts
162import { rcp } from '@kit.RemoteCommunicationKit';
163import { connection } from '@kit.NetworkKit';
164import { BusinessError } from '@kit.BasicServicesKit';
165
166let session = rcp.createSession();
167
168async function useRcp() {
169  /* 建立rcp请求 */
170  try {
171    const request = await session.get('https://www.example.com');
172    console.info(request.statusCode.toString());
173  } catch (e) {
174    console.error(e.code.toString());
175  }
176}
177
178async function rcpTest() {
179  const netConnection = connection.createNetConnection();
180  netConnection.on('netAvailable', async (netHandle: connection.NetHandle) => {
181    /* 发生默认网络切换,重新建立session */
182    session.close();
183    session = rcp.createSession();
184    useRcp();
185  });
186  try {
187    netConnection.register(() => {
188    });
189    useRcp();
190  } catch (e) {
191    console.error(e.code.toString());
192  }
193}
194```
195
196#### 原网络连接使用Socket模块建立连接
197
198```ts
199import { connection, socket } from '@kit.NetworkKit';
200import { BusinessError } from '@kit.BasicServicesKit';
201
202let sock: socket.TCPSocket = socket.constructTCPSocketInstance();
203
204async function useSocket() {
205  let tcpConnectOptions: socket.TCPConnectOptions = {
206    address: {
207      address: '192.168.xx.xxx',
208      port: 8080
209    },
210    timeout: 6000
211  }
212
213  /* 建立socket连接 */
214  sock.connect(tcpConnectOptions, (err: BusinessError) => {
215    if (err) {
216      console.error('connect fail');
217      return;
218    }
219    console.log('connect success');
220
221    /* 通过socket发送数据 */
222    let tcpSendOptions: socket.TCPSendOptions = {
223      data: 'Hello, server!'
224    }
225    sock.send(tcpSendOptions).then(() => {
226      console.log('send success');
227    }).catch((err: BusinessError) => {
228      console.error('send fail');
229    });
230  })
231}
232
233async function socketTest() {
234  const netConnection = connection.createNetConnection();
235  netConnection.on('netAvailable', async (netHandle: connection.NetHandle) => {
236    console.log('default network changed');
237    await sock.close();
238    sock = socket.constructTCPSocketInstance();
239    useSocket();
240  });
241  try {
242    netConnection.register(() => {
243    });
244    useSocket();
245  } catch (e) {
246    console.error(e.code.toString());
247  }
248}
249```
250
251#### 原网络连接使用Socket Library建立网络连接
252
253请在监控到默认网络变化后关闭原有Socket并重新建立Socket连接。
254
255## 获取所有注册的网络
256
2571. 声明接口调用所需要的权限:ohos.permission.GET_NETWORK_INFO258此权限级别为normal,在申请权限前,请保证符合[权限使用的基本原则](../security/AccessToken/app-permission-mgmt-overview.md#权限使用的基本原则)。然后参考[访问控制-声明权限](../security/AccessToken/declare-permissions.md)声明对应权限。
259
2602. 从@kit.NetworkKit中导入connection命名空间。
261
2623. 调用getAllNets方法,获取所有处于连接状态的网络列表。
263
264```ts
265// 引入包名
266import { connection } from '@kit.NetworkKit';
267import { BusinessError } from '@kit.BasicServicesKit';
268
269// 构造单例对象
270export class GlobalContext {
271  public netList: connection.NetHandle[] = [];
272  private constructor() {}
273  private static instance: GlobalContext;
274  private _objects = new Map<string, Object>();
275
276  public static getContext(): GlobalContext {
277    if (!GlobalContext.instance) {
278      GlobalContext.instance = new GlobalContext();
279    }
280    return GlobalContext.instance;
281  }
282
283  getObject(value: string): Object | undefined {
284    return this._objects.get(value);
285  }
286
287  setObject(key: string, objectClass: Object): void {
288    this._objects.set(key, objectClass);
289  }
290}
291
292// 获取所有处于连接状态的网络列表
293connection.getAllNets().then((data: connection.NetHandle[]) => {
294  console.info("Succeeded to get data: " + JSON.stringify(data));
295  if (data) {
296    GlobalContext.getContext().netList = data;
297  }
298});
299```
300
301## 根据数据网络查询网络的能力信息及连接信息
302
3031. 声明接口调用所需要的权限:ohos.permission.GET_NETWORK_INFO304此权限级别为normal,在申请权限前,请保证符合[权限使用的基本原则](../security/AccessToken/app-permission-mgmt-overview.md#权限使用的基本原则)。然后参考[访问控制-声明权限](../security/AccessToken/declare-permissions.md)声明对应权限。
305
3062. 从@kit.NetworkKit中导入connection命名空间。
307
3083. 通过调用getDefaultNet方法,获取默认的数据网络(NetHandle);或者通过调用getAllNets方法,获取所有处于连接状态的网络列表(Array\<NetHandle>)。
309
3104. 调用getNetCapabilities方法,获取NetHandle对应网络的能力信息。能力信息包含了网络类型(蜂窝网络、Wi-Fi网络、以太网网络等)、网络具体能力等网络信息。
311
3125. 调用getConnectionProperties方法,获取NetHandle对应网络的连接信息。
313
314```ts
315import { connection } from '@kit.NetworkKit';
316import { BusinessError } from '@kit.BasicServicesKit';
317
318// 构造单例对象
319export class GlobalContext {
320  public netList: connection.NetHandle[] = [];
321  public netHandle: connection.NetHandle|null = null;
322  private constructor() {}
323  private static instance: GlobalContext;
324  private _objects = new Map<string, Object>();
325
326  public static getContext(): GlobalContext {
327    if (!GlobalContext.instance) {
328      GlobalContext.instance = new GlobalContext();
329    }
330    return GlobalContext.instance;
331  }
332
333  getObject(value: string): Object | undefined {
334    return this._objects.get(value);
335  }
336
337  setObject(key: string, objectClass: Object): void {
338    this._objects.set(key, objectClass);
339  }
340}
341
342// 调用getDefaultNet方法,获取默认的数据网络(NetHandle)
343connection.getDefaultNet().then((data:connection.NetHandle) => {
344  if (data.netId == 0) {
345    // 当前无默认网络时,获取的netHandler的netid为0,属于异常情况,需要额外处理
346    return;
347  }
348  if (data) {
349    console.info("getDefaultNet get data: " + JSON.stringify(data));
350    GlobalContext.getContext().netHandle = data;
351    // 获取netHandle对应网络的能力信息。能力信息包含了网络类型、网络具体能力等网络信息
352    connection.getNetCapabilities(GlobalContext.getContext().netHandle).then(
353      (data: connection.NetCapabilities) => {
354      console.info("getNetCapabilities get data: " + JSON.stringify(data));
355      // 获取网络类型(bearerTypes)
356      let bearerTypes: Set<number> = new Set(data.bearerTypes);
357      let bearerTypesNum = Array.from(bearerTypes.values());
358      for (let item of bearerTypesNum) {
359        if (item == 0) {
360          // 蜂窝网
361          console.log(JSON.stringify("BEARER_CELLULAR"));
362        } else if (item == 1) {
363          // Wi-Fi网络
364          console.log(JSON.stringify("BEARER_WIFI"));
365        } else if (item == 3) {
366          // 以太网网络
367          console.log(JSON.stringify("BEARER_ETHERNET"));
368        }
369      }
370
371      // 获取网络具体能力(networkCap)
372      let itemNumber : Set<number> = new Set(data.networkCap);
373      let dataNumber = Array.from(itemNumber.values());
374      for (let item of dataNumber) {
375        if (item == 0) {
376          // 表示网络可以访问运营商的MMSC(Multimedia Message Service,多媒体短信服务)发送和接收彩信
377          console.log(JSON.stringify("NET_CAPABILITY_MMS"));
378        } else if (item == 11) {
379          // 表示网络流量未被计费
380          console.log(JSON.stringify("NET_CAPABILITY_NOT_METERED"));
381        } else if (item == 12) {
382          // 表示该网络应具有访问Internet的能力,该能力由网络提供者设置
383          console.log(JSON.stringify("NET_CAPABILITY_INTERNET"));
384        } else if (item == 15) {
385          // 表示网络不使用VPN(Virtual Private Network,虚拟专用网络)
386          console.log(JSON.stringify("NET_CAPABILITY_NOT_VPN"));
387        } else if (item == 16) {
388          // 表示该网络访问Internet的能力被网络管理成功验证,该能力由网络管理模块设置
389          console.log(JSON.stringify("NET_CAPABILITY_VALIDATED"));
390        }
391      }
392    })
393  }
394});
395
396// 获取netHandle对应网络的连接信息。连接信息包含了链路信息、路由信息等
397connection.getConnectionProperties(GlobalContext.getContext().netHandle).then((data: connection.ConnectionProperties) => {
398  console.info("getConnectionProperties get data: " + JSON.stringify(data));
399})
400
401// 调用getAllNets,获取所有处于连接状态的网络列表(Array<NetHandle>)
402connection.getAllNets().then((data: connection.NetHandle[]) => {
403  console.info("getAllNets get data: " + JSON.stringify(data));
404  if (data) {
405    GlobalContext.getContext().netList = data;
406
407    let itemNumber : Set<connection.NetHandle> = new Set(GlobalContext.getContext().netList);
408    let dataNumber = Array.from(itemNumber.values());
409    for (let item of dataNumber) {
410      // 循环获取网络列表每个netHandle对应网络的能力信息
411      connection.getNetCapabilities(item).then((data: connection.NetCapabilities) => {
412        console.info("getNetCapabilities get data: " + JSON.stringify(data));
413      })
414
415      // 循环获取网络列表每个netHandle对应的网络的连接信息
416      connection.getConnectionProperties(item).then((data: connection.ConnectionProperties) => {
417        console.info("getConnectionProperties get data: " + JSON.stringify(data));
418      })
419    }
420  }
421})
422```
423
424## 使用对应网络解析域名,获取所有IP
425
4261. 声明接口调用所需要的权限:ohos.permission.INTERNET
427此权限级别为normal,在申请权限前,请保证符合[权限使用的基本原则](../security/AccessToken/app-permission-mgmt-overview.md#权限使用的基本原则)。然后参考[访问控制-声明权限](../security/AccessToken/declare-permissions.md)声明对应权限。
428
4292. 从@kit.NetworkKit中导入connection命名空间。
430
4313. 调用getAddressesByName方法,使用默认网络解析主机名以获取所有IP地址。
432
433```ts
434// 引入包名
435import { connection } from '@kit.NetworkKit';
436import { BusinessError } from '@kit.BasicServicesKit';
437
438// 使用默认网络解析主机名以获取所有IP地址
439connection.getAddressesByName("xxxx").then((data: connection.NetAddress[]) => {
440  console.info("Succeeded to get data: " + JSON.stringify(data));
441});
442```
443