使用移动网络,初次连接IPv6地址连接成功。关闭再打开移动数据开关后,再次连接IPv6地址,此时连接失败。在订阅网络事件netAvailable时打印连接信息时,发现初次连接,linkAddresses中包含IPv6地址。关闭再打开移动数据开关,此时打印linkAddresses中没有IPv6地址。
问题代码如下:
let conn = connection.createNetConnection(); conn.register((error: BusinessError) => {}); conn.on('netAvailable', ((netHandle: connection.NetHandle) => { let properties = connection.getConnectionPropertiesSync(netHandle); if (properties && properties.linkAddresses) { console.info(LOG_TAG, JSON.stringify(properties.linkAddresses)) } // 连接socket this.connect() }));
日志打印:
03-27 11:10:24.179 A03D00/com.exa...pv6test/JSAPP apppool I ipv6_test [{"address":{"address":"10.74.xxx.6","family":1,"port":0},"prefixLength":32},{"address":{"address":"2409:8915:xxxx:xxxx:8e49","family":2,"port":0},"prefixLength":128}] 03-27 11:10:24.227 A03D00/com.exa...pv6test/JSAPP com.example.ipv6test I ipv6_test socket connect result:true 03-27 11:10:30.012 A03D00/com.exa...pv6test/JSAPP com.example.ipv6test I ipv6_test [{"address":{"address":"10.103.xxx.203","family":1,"port":0},"prefixLength":32}] 03-27 11:10:30.015 A03D00/com.exa...pv6test/JSAPP com.example.ipv6test I ipv6_test tcp connect error:{"code":2301101,"message":"Network unreachable"} 03-27 11:10:30.015 A03D00/com.exa...pv6test/JSAPP com.example.ipv6test I ipv6_test socket connect result:false
需确保当前的IPv6链路可用。
核心代码如下:
conn.on('netConnectionPropertiesChange', ((date: connection.NetConnectionPropertyInfo) => { for (let i = 0; i < date.connectionProperties.linkAddresses.length; i++) { console.info(LOG_TAG, JSON.stringify(date.connectionProperties.linkAddresses)); if (date.connectionProperties.linkAddresses[i].address.family === 2) { this.flag = true; this.connect(); break; } else { this.flag = false; } } }));
日志打印:

完整样例参考:
import { socket } from '@kit.NetworkKit'; import { connection } from '@kit.NetworkKit'; const LOG_TAG = 'hm-->'; @Entry @Component struct Index { flag: boolean = false; /** * connect */ connect() { // 需替换有效的IPv6地址 let address = '2409:8C3C:0904:x::x:xx'; let port = 8206; // 创建相应协议的Socket对象 let tcpSocket = new TcpSocket(); tcpSocket.createSocket(); // 连接服务器ip tcpSocket.connectSocket(address, port).then(res => { console.info(LOG_TAG, 'socket connect result:', res); }).catch((rej: Error) => { console.info(LOG_TAG, 'socket connect error:', rej); }); } aboutToAppear(): void { let conn = connection.createNetConnection(); conn.register(() => { }); conn.on('netConnectionPropertiesChange', ((date: connection.NetConnectionPropertyInfo) => { for (let i = 0; i < date.connectionProperties.linkAddresses.length; i++) { console.info(LOG_TAG, JSON.stringify(date.connectionProperties.linkAddresses)); if (date.connectionProperties.linkAddresses[i].address.family === 2) { this.flag = true; this.connect(); break; } else { this.flag = false; } } })); } build() { Column() { Button('连接tcpSocket') .onClick(() => { if (this.flag) { this.connect(); } }) } .width('100%') .height('100%') .justifyContent(FlexAlign.Center) } } class TcpSocket implements BaseSocket { private tcpSocket: socket.TCPSocket | null = null; /** * 创建Socket */ async createSocket(): Promise<boolean> { try { if (this.tcpSocket) { this.tcpSocket.close(); this.tcpSocket = null; } this.tcpSocket = socket.constructTCPSocketInstance(); return true; } catch (e) { console.info(LOG_TAG, 'create socket error', e); } return false; } /** * 连接Socket */ async connectSocket(address: string, port: number): Promise<boolean> { try { if (!this.tcpSocket) { return false; } if (await this.isConnected()) { return true; } //ipv4和ipv6类型设置 let familyValue = 1; if (this.isValidIPv6Format(address)) { familyValue = 2; } await this.tcpSocket.connect({ address: { address: address, port: port, family: familyValue }, timeout: 6000, }); await this.tcpSocket.setExtraOptions({ keepAlive: true, receiveBufferSize: 1024 * 34, sendBufferSize: 1024 * 8, socketTimeout: 6000 }); return true; } catch (e) { console.info(LOG_TAG, 'tcp connect error', e); } return false; }; /** * 判断是否连接 */ async isConnected(): Promise<boolean> { if (!this.tcpSocket) { return false; } ; try { let state: socket.SocketStateBase = await this.tcpSocket.getState(); if (state.isConnected) { return true; } } catch (e) { } return false; }; /** * 判断是否是IPv6 */ private isValidIPv6Format(ip: string): boolean { const IPv4Segment = '(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'; const IPv4Address = `(${IPv4Segment}[.]){3}${IPv4Segment}`; const IPv6Segment = '(?:[0-9a-fA-F]{1,4})'; const ipRegex = new RegExp('^(' + `(?:${IPv6Segment}:){7}(?:${IPv6Segment}|:)|` + `(?:${IPv6Segment}:){6}(?:${IPv4Address}|:${IPv6Segment}|:)|` + `(?:${IPv6Segment}:){5}(?::${IPv4Address}|(:${IPv6Segment}){1,2}|:)|` + `(?:${IPv6Segment}:){4}(?:(:${IPv6Segment}){0,1}:${IPv4Address}|(:${IPv6Segment}){1,3}|:)|` + `(?:${IPv6Segment}:){3}(?:(:${IPv6Segment}){0,2}:${IPv4Address}|(:${IPv6Segment}){1,4}|:)|` + `(?:${IPv6Segment}:){2}(?:(:${IPv6Segment}){0,3}:${IPv4Address}|(:${IPv6Segment}){1,5}|:)|` + `(?:${IPv6Segment}:){1}(?:(:${IPv6Segment}){0,4}:${IPv4Address}|(:${IPv6Segment}){1,6}|:)|` + `(?::((?::${IPv6Segment}){0,5}:${IPv4Address}|(?::${IPv6Segment}){1,7}|:))` + ')(%[0-9a-zA-Z.]{1,})?$'); let flag = ipRegex.test(ip); return flag; }; } /** * Socket协议类型 */ export enum SocketType { TCP, TLS } ; /** * 实现统一的接口(tcp/tls) */ export interface BaseSocket { createSocket(localIp: string, port: number): Promise<boolean>; connectSocket(address: string, port: number): Promise<boolean>; }