WiFi P2P简介

基本原理

WiFi Direct协议是Wi-Fi联盟发展、支持与授予认证的一套软件协议,也被称为Wi-Fi点对点(Wi-Fi Peer-to-Peer,简称P2P)。这套协议允许无线网络中的设备无需通过无线路由器即可相互连接,以点对点的方式直接与另一个 WiFi 设备连线,进行数据高速传输。

通常A与B通信是通过服务器转发数据。

P2P则可以实现A与B直接通信。

技术特点

  • 连接方式:允许 WiFi 设备直接连接,无需通过 AP,从而简化连接流程,提高了数据传输的便捷性。
  • 传输性能:在传输速度与传输距离方面比蓝牙有大幅度提升,最大传输距离可达 200 米,最大传输速度为 250Mbps。
  • 加密机制:支持 WPA2 加密机制,确保数据传输的安全性。

应用场景

  • 文件传输:可以在手机和平板之间快速传输照片、视频等大文件。
  • 内容共享:在会议中直接通过电脑展示手机内容,或在不同设备间共享应用。
  • 文档打印:直接连接打印机进行打印。
  • 数据同步:在设备间同步数据。
  • 娱乐应用:支持近距离的设备互联,适用于游戏、聊天、车机交互。

方案描述

通过wifiManager实现P2P连接,前提需要打开设备WLAN开关,整体方案分为建立P2P连接和P2P连接场景验证两个部分:

  • 建立P2P连接: 发现设备并与P2P设备建立连接。
  • P2P连接场景验证:验证P2P连接后的socket通信,模拟用户与车机交互。

建立P2P连接

  1. 发现设备:P2P连接需要先发现P2P设备才能进行连接。

    1. 注册发现设备状态监听。注册发现设备状态改变事件,注册事件可通过回调监听设备发现服务是否开启成功。

      aboutToAppear(): void {
        // 注册发现设备状态监听
        wifiManager.on("p2pDiscoveryChange", this.recvP2pDiscoveryChangeFunc);
      }
    在业务退出时,要调用wifiManager.off\('p2pDiscoveryChange'\)接口注销注册回调。

    ```
    aboutToDisappear():
      // 注销发现设备状态监听
      wifiManager.off("p2pDiscoveryChange", this.recvP2pDiscoveryChangeFunc);
    }
    ```

    发现设备回调事件: 0- 初始状态。 1-发现成功。

    ```
    // 发现设备状态改变事件。
    recvP2pDiscoveryChangeFunc = (result: number) => {
      promptAction.showToast({
        message: result == 1 ? '发现设备成功' : '发现设备失败',
        duration: 2000
      });
    }
    ```

    开始发现设备,wifiManager.startDiscoverDevices接口为开启P2P发现设备关键步骤,发现设备状态结果通过监听事件回调。

    ```
    Button('开始发现设备').onClick(() => {
      try {
        wifiManager.startDiscoverDevices();
      } catch (error) {
        console.error("wifiManager.startDiscoverDevices failed:" + JSON.stringify(error));
      }
    })
    ```

2.  获取设备列表。

    当发现设备阶段完成,即发现设备状态监听事件回调为1,此时设备可被p2p设备发现,且通过wifiManager.getP2pPeerDevices可获取对端设备列表。

    ```
    // 获取P2P对端设备列表信息
    getPeerDeviceList() {
      // p2p发现阶段完成,才能正常获取到对端设备列表信息
      this.peerDevices = []
      wifiManager.getP2pPeerDevices((err, data) => {
        if (err) {
          console.error("get P2P peer devices error");
          return;
        }
        console.info("get P2P peer devices: " + JSON.stringify(data));
        this.peerDevices = data
      });
    }
    ```
  1. 建立连接。

    1. 通过已发现设备WifiP2pDevice进行连接。

      建立p2p连接会有连接状态回调,通知连接状态变化,可根据状态变化实现对应逻辑。首先声明监听事件recvP2pConnectionChangeFunc。

      // p2p连接状态改变事件
      recvP2pConnectionChangeFunc = (result: wifiManager.WifiP2pLinkedInfo) => {
        console.info("p2p connection change receive event: " + JSON.stringify(result));
        if (result.connectState == 1) {
          promptAction.showToast({
            message: '已连接',
            duration: 2000
          });
        }
      }
    再通过wifiManager.on\("p2pConnectionChange"\)注册p2p连接状态监听。

    ```
    aboutToAppear(): void {
      // 注册p2p连接状态监听
      wifiManager.on("p2pConnectionChange", this.recvP2pConnectionChangeFunc)
    }
    ```

    p2p连接状态监听在业务结束时通过wifiManager.off\("p2pConnectionChange"\)注销。

    ```
    aboutToDisappear(): void {
      // 注销p2p连接状态监听
      wifiManager.off('p2pConnectionChange',this.recvP2pConnectionChangeFunc)
    }
    ```

    从扫描到的设备列表中,选择需要连接的设备通过wifiManager.p2pConnect进行P2P连接。

    ```
    // 建立对端连接
    connectToPeerDevice(device: wifiManager.WifiP2pDevice) {
      let config: wifiManager.WifiP2PConfig = {
        deviceAddress: device.deviceAddress,
        deviceAddressType: device.deviceAddressType,
        netId: 0,
        passphrase: "",
        groupName: "",
        goBand: 0,
      }
      try {
        wifiManager.p2pConnect(config);
      } catch (e) {
        console.error("wifiManager.p2pConnect error ", e.code);
      }
    }
    ```

2.  获取P2P连接群组信息。

    p2p连接成功后获取当前群组信息,获取goIpAddress,通过goIpAddress可与对端服务进行通信。

    ```
    // 获取当前群组信息
    getGroupInfo(){
      wifiManager.getCurrentGroup((err, data) => {
        if (err) {
          console.error("get current P2P group error");
          return;
        }
        console.info("get current P2P group: " + JSON.stringify(data));
        this.goIpAddress = data.goIpAddress
      });
    }
    ```

P2P连接场景验证:

1,手机模拟车机系统。

效果图:用户连接车机socket成功

const tcpServer = socket.constructTCPSocketServerInstance()
export function createServer(callback: Callback<boolean>): void {
  let ipAddress : socket.NetAddress = {} as socket.NetAddress
  ipAddress.address = "0.0.0.0"
  ipAddress.port = 4651
  tcpServer.listen(ipAddress, (err: BusinessError) => {
    if (err) {
      console.log("listen fail");
      return
    }
    console.log("listen success");
    promptAction.showToast({
      message: JSON.stringify('listen success'),
      duration: 2000
    })
  })

  class SocketInfo {
    message: ArrayBuffer = new ArrayBuffer(1);
    remoteInfo: socket.SocketRemoteInfo = {} as socket.SocketRemoteInfo;
  }

  // Listen client connect to server
  tcpServer.on("connect", (connection: socket.TCPSocketConnection) => {
    tcpConnectArray.pop()
    tcpConnectArray.push(connection)

    // Listen connection closed
    connection.on("close", () => {
      console.info("on close success")
    });

    // Listen receive message
    connection.on("message", (value: SocketInfo) => {
      let buffer = value.message
      let dataView = new DataView(buffer);
      let str = ""
      for (let i = 0; i < dataView.byteLength; ++i) {
        str += String.fromCharCode(dataView.getUint8(i))
      }
      // Response to client
      response()
      // Toast message
      promptAction.showToast({
        message: JSON.stringify(str),
        duration: 2000
      })
    })

    // Send data to the client for Connection state.
    let tcpSendOptions : socket.TCPSendOptions = {} as socket.TCPSendOptions
    tcpSendOptions.data = 'Hello, client, connect success!'
    connection.send(tcpSendOptions, (err: BusinessError) => {
      if (err) {
        console.log("send fail")
        return
      }
      console.log("send success")
    })
  })
}

2,手机应用连接车机服务

效果图:连接车机socket成功

通过p2p连接获取到的goIpAddress连接车机Socket服务:

// 连接车机Socket服务
createSocketClient(){
  let ipAddress: socket.NetAddress = {} as socket.NetAddress;
  ipAddress.address = this.goIpAddress;
  ipAddress.port = 4651;
  let tcpConnect: socket.TCPConnectOptions = {} as socket.TCPConnectOptions;
  tcpConnect.address = ipAddress;
  tcpConnect.timeout = 6000;
  tcp.connect(tcpConnect, (err: BusinessError) => {
    if (err) {
      console.log('connect fail' + JSON.stringify(err));
      return;
    }
    console.log('connect success');
  });
}

3,手机应用向车机服务发送消息

效果图:车机收到用户发送的‘hello,my car!’

// 发送消息
let clientSendOptions: socket.TCPSendOptions = {} as socket.TCPSendOptions;
export function sendMsg() {
  clientSendOptions.data = 'hello,my car!';
  tcp.send(clientSendOptions, (err: BusinessError) => {
    if (err) {
      console.log('sendMsg fail ');
      return;
    }
    console.warn('fxm debug : client sendMsg success');
  })
}

4,车机服务响应手机应用消息

效果图:用户收到车机响应的‘hello,have a good day!’

在创建的车机socket server中,有接受消息的监听,监听到手机应用请求后,做出响应。

export function response() {
  let connection: socket.TCPSocketConnection = tcpConnectArray[0];
  let tcpSendOptions: socket.TCPSendOptions = {} as socket.TCPSendOptions
  tcpSendOptions.data = 'hello,have a good day!'
  connection.send(tcpSendOptions, (err: BusinessError) => {
    if (err) {
      console.log("response fail")
      return
    }
    console.log("response success")
  })
}

5,车机服务向手机应用推送消息

效果图:用户收到车机推送的‘hello, the car has reached its destination!’

车机系统也可向手机应用主动推送消息。

let tcpSendOptions : socket.TCPSendOptions = {} as socket.TCPSendOptions
tcpSendOptions.data = 'hello, the car has reached its destination!'
connection.send(tcpSendOptions, (err: BusinessError) => {
  if (err) {
    console.log("send fail")
    return
  }
  console.log("send success")
})

到此则实现p2p连接后的socket通信验证。


HarmonyOS码上奇行
11.4k 声望4.1k 粉丝

欢迎关注 HarmonyOS 开发者社区:[链接]