HarmonyOS APP点对点直连通信

举报
Jack20 发表于 2026/06/19 20:09:35 2026/06/19
【摘要】 HarmonyOS APP点对点直连通信传统的WiFi通信需要路由器作为中转,但有时候我们希望两台设备直接"对话"——不经过任何中间设备,速度更快、延迟更低。这就是WiFi P2P(Wi-Fi Direct)的用武之地。今天咱们就来聊聊鸿蒙系统中的WiFi P2P技术,看看如何实现设备间的点对点直连通信。 一、背景与动机 1.1 WiFi P2P的优势与应用场景WiFi P2P(也叫Wi-...

HarmonyOS APP点对点直连通信

传统的WiFi通信需要路由器作为中转,但有时候我们希望两台设备直接"对话"——不经过任何中间设备,速度更快、延迟更低。这就是WiFi P2P(Wi-Fi Direct)的用武之地。今天咱们就来聊聊鸿蒙系统中的WiFi P2P技术,看看如何实现设备间的点对点直连通信。

一、背景与动机

1.1 WiFi P2P的优势与应用场景

WiFi P2P(也叫Wi-Fi Direct)允许两台设备在不需要路由器的情况下直接建立WiFi连接。相比传统方案,它有这些优势:

对比项 传统WiFi WiFi热点 WiFi P2P
是否需要路由器 需要 不需要 不需要
连接速度 受路由器限制 较快 最快
配置复杂度 中等 较高 低(一键连接)
功耗 中等
同时连接数 有限

典型应用场景

  1. 快速文件传输:两台手机间传输大文件,速度可达数百Mbps
  2. 无线投屏:手机直接投屏到电视,无需同一WiFi
  3. 多人游戏:本地多人游戏,低延迟通信
  4. 打印机连接:手机直接连接WiFi打印机
  5. 设备发现:快速发现附近的设备

1.2 WiFi P2P工作原理

WiFi P2P的核心是"Group Owner(GO)"机制。连接时,一台设备会自动成为GO(类似热点),另一台成为Client。这个过程对用户是透明的,系统自动协商决定。
图片.png

二、核心原理

2.1 P2P连接流程详解

完整的P2P连接包含发现、连接、数据传输三个阶段:
图片.png

2.2 P2P设备信息结构

interface P2pDeviceInfo {
  // 设备名称
  deviceName: string;
  
  // 设备MAC地址
  deviceAddress: string;
  
  // 设备类型(手机、电视、打印机等)
  primaryDeviceType: string;
  
  // 是否为Group Owner
  isGroupOwner: boolean;
  
  // WPS配置方法
  wpsConfigMethod: number;
  
  // 设备状态
  deviceStatus: P2pDeviceStatus;
  
  // 信号强度
  signalStrength?: number;
}

2.3 GO协商机制

GO协商是P2P的核心机制,决定了哪台设备成为"热点":

协商因素

  1. Intent值:每台设备有一个3-15的Intent值,值越大越倾向于成为GO
  2. 设备能力:有些设备(如电视)更适合做GO
  3. 电量状态:低电量设备倾向于做Client
// Intent值说明
const P2P_INTENT = {
  MIN: 0,      // 最小值,倾向于做Client
  LOW: 3,      // 低优先级
  NORMAL: 7,   // 正常优先级
  HIGH: 11,    // 高优先级
  MAX: 15      // 最大值,倾向于做GO
};

// 设置Intent值
await wifiP2p.setP2pIntent(P2P_INTENT.HIGH); // 更倾向于成为GO

三、代码实战

3.1 P2P管理核心类封装

import wifiP2p from '@ohos.wifiP2p';
import { BusinessError } from '@ohos.base';

/**
 * WiFi P2P管理器
 * 封装P2P发现、连接、通信等核心功能
 */
export class WifiP2pManager {
  private static instance: WifiP2pManager;
  private discoveredDevices: Array<wifiP2p.WifiP2pDevice> = [];
  private connectedDevice: wifiP2p.WifiP2pDevice | null = null;
  private p2pGroupInfo: wifiP2p.WifiP2pGroupInfo | null = null;

  // 回调函数
  private onDeviceDiscovered: ((device: wifiP2p.WifiP2pDevice) => void) | null = null;
  private onConnectionChanged: ((state: wifiP2p.P2pConnectState) => void) | null = null;
  private onGroupChanged: ((info: wifiP2p.WifiP2pGroupInfo) => void) | null = null;

  private constructor() {
    this.initEventListeners();
  }

  /**
   * 获取单例实例
   */
  public static getInstance(): WifiP2pManager {
    if (!WifiP2pManager.instance) {
      WifiP2pManager.instance = new WifiP2pManager();
    }
    return WifiP2pManager.instance;
  }

  /**
   * 初始化事件监听
   */
  private initEventListeners(): void {
    // 监听P2P设备发现
    wifiP2p.on('p2pDeviceChange', (device: wifiP2p.WifiP2pDevice) => {
      console.info(`[P2P] 发现设备: ${device.deviceName}`);
      
      // 更新设备列表
      const index = this.discoveredDevices.findIndex(
        d => d.deviceAddress === device.deviceAddress
      );
      if (index >= 0) {
        this.discoveredDevices[index] = device;
      } else {
        this.discoveredDevices.push(device);
      }
      
      if (this.onDeviceDiscovered) {
        this.onDeviceDiscovered(device);
      }
    });

    // 监听连接状态变化
    wifiP2p.on('p2pConnectionChange', (state: wifiP2p.P2pConnectState) => {
      console.info(`[P2P] 连接状态: ${state}`);
      if (this.onConnectionChanged) {
        this.onConnectionChanged(state);
      }
    });

    // 监听P2P组变化
    wifiP2p.on('p2pGroupChange', () => {
      this.updateGroupInfo();
    });

    // 监听本设备状态变化
    wifiP2p.on('p2pStateChange', (state: number) => {
      const stateText = state === 1 ? '可用' : '不可用';
      console.info(`[P2P] 状态变化: ${stateText}`);
    });
  }

  /**
   * 开启P2P功能
   */
  public async enableP2p(): Promise<boolean> {
    try {
      await wifiP2p.enableP2p();
      console.info('[P2P] 已开启');
      return true;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[P2P] 开启失败: ${err.message}`);
      return false;
    }
  }

  /**
   * 关闭P2P功能
   */
  public async disableP2p(): Promise<boolean> {
    try {
      await wifiP2p.disableP2p();
      console.info('[P2P] 已关闭');
      return true;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[P2P] 关闭失败: ${err.message}`);
      return false;
    }
  }

  /**
   * 发起设备发现
   */
  public async startDiscovery(): Promise<boolean> {
    try {
      // 清空已发现的设备列表
      this.discoveredDevices = [];
      
      await wifiP2p.discoverDevices();
      console.info('[P2P] 开始发现设备');
      return true;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[P2P] 发现失败: ${err.message}`);
      return false;
    }
  }

  /**
   * 停止设备发现
   */
  public async stopDiscovery(): Promise<boolean> {
    try {
      await wifiP2p.stopDiscoverDevices();
      console.info('[P2P] 停止发现');
      return true;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[P2P] 停止失败: ${err.message}`);
      return false;
    }
  }

  /**
   * 获取已发现的设备列表
   */
  public getDiscoveredDevices(): Array<wifiP2p.WifiP2pDevice> {
    return this.discoveredDevices;
  }

  /**
   * 连接到指定设备
   * @param deviceAddress 设备MAC地址
   * @param configMethod WPS配置方法
   */
  public async connectToDevice(
    deviceAddress: string,
    configMethod: wifiP2p.WpsConfigMethod = wifiP2p.WpsConfigMethod.WPS_PBC
  ): Promise<boolean> {
    try {
      // 构建连接配置
      const config: wifiP2p.WifiP2pConfig = {
        deviceAddress: deviceAddress,
        wpsInfo: {
          wpsConfigMethod: configMethod
        }
      };

      await wifiP2p.connect(config);
      console.info(`[P2P] 正在连接到 ${deviceAddress}`);
      return true;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[P2P] 连接失败: ${err.message}`);
      return false;
    }
  }

  /**
   * 使用PIN码连接
   * @param deviceAddress 设备地址
   * @param pin PIN码
   */
  public async connectWithPin(deviceAddress: string, pin: string): Promise<boolean> {
    try {
      const config: wifiP2p.WifiP2pConfig = {
        deviceAddress: deviceAddress,
        wpsInfo: {
          wpsConfigMethod: wifiP2p.WpsConfigMethod.WPS_PIN_DISPLAY,
          pin: pin
        }
      };

      await wifiP2p.connect(config);
      console.info(`[P2P] 使用PIN连接: ${pin}`);
      return true;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[P2P] PIN连接失败: ${err.message}`);
      return false;
    }
  }

  /**
   * 断开P2P连接
   */
  public async disconnect(): Promise<boolean> {
    try {
      await wifiP2p.disconnect();
      this.connectedDevice = null;
      this.p2pGroupInfo = null;
      console.info('[P2P] 已断开连接');
      return true;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[P2P] 断开失败: ${err.message}`);
      return false;
    }
  }

  /**
   * 创建P2P组(成为GO)
   */
  public async createGroup(): Promise<boolean> {
    try {
      await wifiP2p.createGroup();
      console.info('[P2P] 已创建组(成为GO)');
      return true;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[P2P] 创建组失败: ${err.message}`);
      return false;
    }
  }

  /**
   * 删除P2P组
   */
  public async removeGroup(): Promise<boolean> {
    try {
      await wifiP2p.removeGroup();
      console.info('[P2P] 已删除组');
      return true;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[P2P] 删除组失败: ${err.message}`);
      return false;
    }
  }

  /**
   * 获取当前组信息
   */
  public async getGroupInfo(): Promise<wifiP2p.WifiP2pGroupInfo | null> {
    try {
      const info = await wifiP2p.getCurrentGroup();
      this.p2pGroupInfo = info;
      console.info(`[P2P] 组信息: GO=${info.isGroupOwner}, 地址=${info.groupOwnerAddress}`);
      return info;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[P2P] 获取组信息失败: ${err.message}`);
      return null;
    }
  }

  /**
   * 更新组信息
   */
  private async updateGroupInfo(): Promise<void> {
    const info = await this.getGroupInfo();
    if (info && this.onGroupChanged) {
      this.onGroupChanged(info);
    }
  }

  /**
   * 获取P2P连接信息
   */
  public async getLinkedInfo(): Promise<wifiP2p.WifiP2pLinkedInfo | null> {
    try {
      const info = await wifiP2p.getP2pLinkedInfo();
      console.info(`[P2P] 连接信息: ${info.connectState}`);
      return info;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[P2P] 获取连接信息失败: ${err.message}`);
      return null;
    }
  }

  /**
   * 设置回调函数
   */
  public setOnDeviceDiscovered(callback: (device: wifiP2p.WifiP2pDevice) => void): void {
    this.onDeviceDiscovered = callback;
  }

  public setOnConnectionChanged(callback: (state: wifiP2p.P2pConnectState) => void): void {
    this.onConnectionChanged = callback;
  }

  public setOnGroupChanged(callback: (info: wifiP2p.WifiP2pGroupInfo) => void): void {
    this.onGroupChanged = callback;
  }

  /**
   * 移除所有监听
   */
  public removeAllListeners(): void {
    wifiP2p.off('p2pDeviceChange');
    wifiP2p.off('p2pConnectionChange');
    wifiP2p.off('p2pGroupChange');
    wifiP2p.off('p2pStateChange');
    console.info('[P2P] 已移除所有监听');
  }

  /**
   * 判断是否为Group Owner
   */
  public async isGroupOwner(): Promise<boolean> {
    const info = await this.getGroupInfo();
    return info ? info.isGroupOwner : false;
  }

  /**
   * 获取对方设备的IP地址
   */
  public async getPeerIpAddress(): Promise<string | null> {
    const info = await this.getGroupInfo();
    if (!info) return null;

    if (info.isGroupOwner) {
      // 本设备是GO,对方是Client
      // 需要从组信息中获取Client的IP
      return info.groupOwnerAddress; // 简化处理
    } else {
      // 本设备是Client,对方是GO
      return info.groupOwnerAddress;
    }
  }
}

3.2 P2P设备发现与连接UI

import { WifiP2pManager } from './WifiP2pManager';
import wifiP2p from '@ohos.wifiP2p';

@Entry
@Component
struct P2pConnectPage {
  private p2pManager: WifiP2pManager = WifiP2pManager.getInstance();

  @State isP2pEnabled: boolean = false;
  @State isDiscovering: boolean = false;
  @State discoveredDevices: Array<wifiP2p.WifiP2pDevice> = [];
  @State isConnected: boolean = false;
  @State connectedDeviceName: string = '';
  @State isGroupOwner: boolean = false;
  @State groupInfo: string = '';

  aboutToAppear(): void {
    this.checkP2pState();
    this.registerCallbacks();
  }

  aboutToDisappear(): void {
    this.p2pManager.removeAllListeners();
  }

  /**
   * 检查P2P状态
   */
  async checkP2pState(): Promise<void> {
    // 假设有方法检查状态
    this.isP2pEnabled = true; // 实际需要调用API
  }

  /**
   * 注册回调
   */
  registerCallbacks(): void {
    // 设备发现回调
    this.p2pManager.setOnDeviceDiscovered((device: wifiP2p.WifiP2pDevice) => {
      this.discoveredDevices = this.p2pManager.getDiscoveredDevices();
    });

    // 连接状态回调
    this.p2pManager.setOnConnectionChanged((state: wifiP2p.P2pConnectState) => {
      if (state === wifiP2p.P2pConnectState.P2P_CONNECTED) {
        this.isConnected = true;
        this.updateConnectionInfo();
      } else {
        this.isConnected = false;
        this.connectedDeviceName = '';
      }
    });

    // 组信息回调
    this.p2pManager.setOnGroupChanged((info: wifiP2p.WifiP2pGroupInfo) => {
      this.isGroupOwner = info.isGroupOwner;
      this.groupInfo = info.isGroupOwner ? '本设备为GO' : '对方为GO';
    });
  }

  /**
   * 更新连接信息
   */
  async updateConnectionInfo(): Promise<void> {
    const info = await this.p2pManager.getGroupInfo();
    if (info) {
      this.isGroupOwner = info.isGroupOwner;
      this.groupInfo = `GO: ${info.passphrase}`;
    }
  }

  /**
   * 开启P2P
   */
  async enableP2p(): Promise<void> {
    const success = await this.p2pManager.enableP2p();
    if (success) {
      this.isP2pEnabled = true;
    }
  }

  /**
   * 开始发现设备
   */
  async startDiscovery(): Promise<void> {
    this.isDiscovering = true;
    const success = await this.p2pManager.startDiscovery();
    if (!success) {
      this.isDiscovering = false;
    }

    // 设置发现超时
    setTimeout(() => {
      if (this.isDiscovering) {
        this.p2pManager.stopDiscovery();
        this.isDiscovering = false;
      }
    }, 60000); // 60秒超时
  }

  /**
   * 停止发现
   */
  async stopDiscovery(): Promise<void> {
    await this.p2pManager.stopDiscovery();
    this.isDiscovering = false;
  }

  /**
   * 连接到设备
   */
  async connectDevice(device: wifiP2p.WifiP2pDevice): Promise<void> {
    const success = await this.p2pManager.connectToDevice(device.deviceAddress);
    if (success) {
      this.connectedDeviceName = device.deviceName;
    }
  }

  /**
   * 断开连接
   */
  async disconnect(): Promise<void> {
    await this.p2pManager.disconnect();
    this.isConnected = false;
    this.connectedDeviceName = '';
  }

  build() {
    Column() {
      // 标题栏
      Row() {
        Text('WiFi P2P')
          .fontSize(24)
          .fontWeight(FontWeight.Bold)
          .fontColor('#FFFFFF')

        Blank()

        Toggle({ type: ToggleType.Switch, isOn: this.isP2pEnabled })
          .onChange((isOn: boolean) => {
            if (isOn) {
              this.enableP2p();
            } else {
              this.p2pManager.disableP2p();
              this.isP2pEnabled = false;
            }
          })
      }
      .width('100%')
      .padding(20)
      .backgroundColor('#1A1A2E')

      // 连接状态
      if (this.isConnected) {
        Column() {
          Row() {
            Text('已连接')
              .fontSize(16)
              .fontColor('#4CAF50')

            Text(this.connectedDeviceName)
              .fontSize(14)
              .fontColor('#FFFFFF')
              .margin({ left: 10 })
          }
          .width('100%')

          Row() {
            Text(this.groupInfo)
              .fontSize(12)
              .fontColor('#AAAAAA')

            Blank()

            Text(this.isGroupOwner ? 'GO' : 'Client')
              .fontSize(12)
              .fontColor('#F5A623')
          }
          .width('100%')
          .margin({ top: 10 })

          Button('断开连接')
            .width('100%')
            .height(40)
            .backgroundColor('#FF5722')
            .margin({ top: 15 })
            .onClick(() => {
              this.disconnect();
            })
        }
        .width('90%')
        .padding(20)
        .backgroundColor('#16213E')
        .borderRadius(12)
        .margin({ top: 20 })
      }

      // 发现按钮
      if (this.isP2pEnabled && !this.isConnected) {
        Button(this.isDiscovering ? '发现中...' : '发现设备')
          .width('90%')
          .height(50)
          .backgroundColor(this.isDiscovering ? '#666666' : '#4A90E2')
          .enabled(!this.isDiscovering)
          .onClick(() => {
            this.startDiscovery();
          })
          .margin({ top: 20 })

        if (this.isDiscovering) {
          Button('停止发现')
            .width('90%')
            .height(40)
            .backgroundColor('#F5A623')
            .margin({ top: 10 })
            .onClick(() => {
              this.stopDiscovery();
            })
        }
      }

      // 设备列表
      if (this.discoveredDevices.length > 0) {
        Column() {
          Text(`发现 ${this.discoveredDevices.length} 台设备`)
            .fontSize(16)
            .fontColor('#FFFFFF')
            .width('100%')
            .margin({ bottom: 15 })

          List() {
            ForEach(this.discoveredDevices, (device: wifiP2p.WifiP2pDevice) => {
              ListItem() {
                Row() {
                  Column() {
                    Text(device.deviceName || '未知设备')
                      .fontSize(16)
                      .fontColor('#FFFFFF')

                    Text(device.deviceAddress)
                      .fontSize(12)
                      .fontColor('#AAAAAA')
                      .margin({ top: 5 })
                  }
                  .alignItems(HorizontalAlign.Start)
                  .layoutWeight(1)

                  Button('连接')
                    .width(70)
                    .height(35)
                    .backgroundColor('#4A90E2')
                    .onClick(() => {
                      this.connectDevice(device);
                    })
                }
                .width('100%')
                .padding(15)
                .backgroundColor('#1A1A2E')
                .borderRadius(8)
                .margin({ bottom: 10 })
              }
            }, (device: wifiP2p.WifiP2pDevice) => device.deviceAddress)
          }
          .width('100%')
          .layoutWeight(1)
        }
        .width('90%')
        .padding(20)
        .backgroundColor('#16213E')
        .borderRadius(12)
        .margin({ top: 20 })
        .layoutWeight(1)
      }

      // 提示信息
      if (!this.isP2pEnabled) {
        Column() {
          Text('P2P功能未开启')
            .fontSize(18)
            .fontColor('#AAAAAA')

          Text('请开启WiFi P2P功能')
            .fontSize(14)
            .fontColor('#666666')
            .margin({ top: 10 })
        }
        .margin({ top: 100 })
      }
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#0F0F1A')
  }
}

3.3 P2P数据传输实现

P2P连接建立后,需要通过Socket进行数据传输:

import socket from '@ohos.net.socket';
import { WifiP2pManager } from './WifiP2pManager';

/**
 * P2P数据传输管理器
 * 处理Socket通信
 */
export class P2pDataTransfer {
  private static instance: P2pDataTransfer;
  private p2pManager: WifiP2pManager = WifiP2pManager.getInstance();
  private serverSocket: socket.TCPSocket | null = null;
  private clientSocket: socket.TCPSocket | null = null;
  private port: number = 8888;
  private isServer: boolean = false;

  // 数据接收回调
  private onDataReceived: ((data: string) => void) | null = null;

  private constructor() {}

  public static getInstance(): P2pDataTransfer {
    if (!P2pDataTransfer.instance) {
      P2pDataTransfer.instance = new P2pDataTransfer();
    }
    return P2pDataTransfer.instance;
  }

  /**
   * 初始化数据通道
   * GO作为服务端,Client作为客户端
   */
  public async initDataChannel(): Promise<boolean> {
    const isGO = await this.p2pManager.isGroupOwner();
    this.isServer = isGO;

    if (isGO) {
      // 作为服务端,监听连接
      return await this.startServer();
    } else {
      // 作为客户端,连接服务端
      return await this.connectToServer();
    }
  }

  /**
   * 启动服务端(GO)
   */
  private async startServer(): Promise<boolean> {
    try {
      this.serverSocket = socket.constructTCPSocketInstance();

      // 绑定端口
      await this.serverSocket.bind({
        address: '0.0.0.0',
        port: this.port,
        family: 1 // IPv4
      });

      // 监听连接
      this.serverSocket.on('connect', (client: socket.TCPSocket) => {
        console.info('[P2P传输] 客户端已连接');
        this.clientSocket = client;
        this.setupDataReceiver(client);
      });

      await this.serverSocket.listen(5);
      console.info(`[P2P传输] 服务端已启动,端口: ${this.port}`);
      return true;
    } catch (error) {
      console.error('[P2P传输] 启动服务端失败:', error);
      return false;
    }
  }

  /**
   * 连接到服务端(Client)
   */
  private async connectToServer(): Promise<boolean> {
    try {
      const peerIp = await this.p2pManager.getPeerIpAddress();
      if (!peerIp) {
        console.error('[P2P传输] 无法获取对方IP');
        return false;
      }

      this.clientSocket = socket.constructTCPSocketInstance();

      // 连接服务端
      await this.clientSocket.connect({
        address: peerIp,
        port: this.port,
        family: 1,
        timeout: 10000
      });

      console.info(`[P2P传输] 已连接到服务端: ${peerIp}:${this.port}`);
      this.setupDataReceiver(this.clientSocket);
      return true;
    } catch (error) {
      console.error('[P2P传输] 连接服务端失败:', error);
      return false;
    }
  }

  /**
   * 设置数据接收器
   */
  private setupDataReceiver(socket: socket.TCPSocket): void {
    socket.on('message', (value: socket.SocketMessageInfo) => {
      const data = String.fromCharCode.apply(null, Array.from(value.message));
      console.info(`[P2P传输] 收到数据: ${data.length} 字节`);

      if (this.onDataReceived) {
        this.onDataReceived(data);
      }
    });

    socket.on('close', () => {
      console.info('[P2P传输] 连接已关闭');
      this.clientSocket = null;
    });

    socket.on('error', (err: socket.SocketError) => {
      console.error('[P2P传输] Socket错误:', err);
    });
  }

  /**
   * 发送数据
   */
  public async sendData(data: string): Promise<boolean> {
    if (!this.clientSocket) {
      console.error('[P2P传输] 未连接');
      return false;
    }

    try {
      const buffer = new ArrayBuffer(data.length);
      const view = new Uint8Array(buffer);
      for (let i = 0; i < data.length; i++) {
        view[i] = data.charCodeAt(i);
      }

      await this.clientSocket.send({
        data: buffer
      });

      console.info(`[P2P传输] 发送成功: ${data.length} 字节`);
      return true;
    } catch (error) {
      console.error('[P2P传输] 发送失败:', error);
      return false;
    }
  }

  /**
   * 发送文件
   * 大文件分块发送
   */
  public async sendFile(filePath: string, onProgress?: (progress: number) => void): Promise<boolean> {
    // 实际项目中需要:
    // 1. 读取文件
    // 2. 分块发送
    // 3. 报告进度
    console.info(`[P2P传输] 发送文件: ${filePath}`);
    return true;
  }

  /**
   * 设置数据接收回调
   */
  public setOnDataReceived(callback: (data: string) => void): void {
    this.onDataReceived = callback;
  }

  /**
   * 关闭数据通道
   */
  public async closeDataChannel(): Promise<void> {
    if (this.clientSocket) {
      await this.clientSocket.close();
      this.clientSocket = null;
    }

    if (this.serverSocket) {
      await this.serverSocket.close();
      this.serverSocket = null;
    }

    console.info('[P2P传输] 数据通道已关闭');
  }
}

四、踩坑与注意事项

4.1 权限配置

// module.json5
{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.GET_WIFI_INFO",
        "reason": "获取WiFi信息"
      },
      {
        "name": "ohos.permission.SET_WIFI_INFO",
        "reason": "修改WiFi设置"
      },
      {
        "name": "ohos.permission.LOCATION",
        "reason": "P2P发现需要位置权限"
      },
      {
        "name": "ohos.permission.INTERNET",
        "reason": "Socket通信需要"
      }
    ]
  }
}

4.2 发现超时处理

坑点:设备发现不会自动停止,需要手动控制。

/**
 * 带超时的设备发现
 */
async function discoverWithTimeout(timeout: number = 60000): Promise<Array<wifiP2p.WifiP2pDevice>> {
  const p2pManager = WifiP2pManager.getInstance();
  
  await p2pManager.startDiscovery();
  
  return new Promise((resolve) => {
    const devices: Array<wifiP2p.WifiP2pDevice> = [];
    
    p2pManager.setOnDeviceDiscovered((device) => {
      devices.push(device);
    });

    setTimeout(async () => {
      await p2pManager.stopDiscovery();
      resolve(devices);
    }, timeout);
  });
}

4.3 连接重试机制

坑点:P2P连接可能失败,需要重试。

/**
 * 带重试的P2P连接
 */
async function connectWithRetry(
  deviceAddress: string,
  maxRetries: number = 3
): Promise<boolean> {
  const p2pManager = WifiP2pManager.getInstance();
  
  for (let i = 0; i < maxRetries; i++) {
    console.info(`[P2P] 连接尝试 ${i + 1}/${maxRetries}`);
    
    const success = await p2pManager.connectToDevice(deviceAddress);
    if (success) {
      // 等待连接结果
      const connected = await waitForConnection(10000);
      if (connected) {
        return true;
      }
    }
    
    // 断开并重试
    await p2pManager.disconnect();
    await delay(2000);
  }
  
  return false;
}

async function waitForConnection(timeout: number): Promise<boolean> {
  return new Promise((resolve) => {
    let resolved = false;
    const timer = setTimeout(() => {
      if (!resolved) {
        resolved = true;
        resolve(false);
      }
    }, timeout);

    const p2pManager = WifiP2pManager.getInstance();
    p2pManager.setOnConnectionChanged((state) => {
      if (!resolved && state === wifiP2p.P2pConnectState.P2P_CONNECTED) {
        resolved = true;
        clearTimeout(timer);
        resolve(true);
      }
    });
  });
}

function delay(ms: number): Promise<void> {
  return new Promise(resolve => setTimeout(resolve, ms));
}

4.4 GO与Client的IP分配

坑点:Client需要知道GO的IP才能建立Socket连接。

/**
 * 获取正确的连接IP
 */
async function getConnectAddress(): Promise<string | null> {
  const p2pManager = WifiP2pManager.getInstance();
  const groupInfo = await p2pManager.getGroupInfo();
  
  if (!groupInfo) return null;
  
  if (groupInfo.isGroupOwner) {
    // 本设备是GO,返回自己的IP
    // 通常GO的IP是192.168.49.1
    return '192.168.49.1';
  } else {
    // 本设备是Client,返回GO的IP
    return groupInfo.groupOwnerAddress;
  }
}

4.5 WiFi与P2P互斥

坑点:某些设备上,WiFi连接和P2P可能互斥。

/**
 * 检查P2P可用性
 */
async function checkP2pAvailability(): Promise<boolean> {
  try {
    // 检查WiFi是否连接
    const wifiLinked = await wifiManager.getLinkedInfo();
    if (wifiLinked && wifiLinked.connState === wifiManager.WifiConnState.WIFI_CONNECTED) {
      console.warn('[P2P] WiFi已连接,P2P可能受限');
      // 某些设备支持并发,某些不支持
      // 需要根据实际情况处理
    }
    
    return true;
  } catch (error) {
    return false;
  }
}

五、HarmonyOS 6适配

5.1 API变更

API HarmonyOS 5 HarmonyOS 6 说明
discoverDevices() 返回void 返回Promise<boolean> 改为异步
connect() 同步返回 异步返回 统一异步模式
新增 - getP2pDeviceInfo() 获取详细设备信息

适配代码

/**
 * HarmonyOS 6 P2P适配
 */
async function discoverDevicesAdaptive(): Promise<boolean> {
  const apiVersion = getApiVersion();

  try {
    if (apiVersion >= 6) {
      // HarmonyOS 6
      const result = await wifiP2p.discoverDevices();
      return result;
    } else {
      // HarmonyOS 5
      await wifiP2p.discoverDevices();
      return true;
    }
  } catch (error) {
    console.error('[P2P] 发现失败:', error);
    return false;
  }
}

5.2 新增功能

HarmonyOS 6增强了P2P能力:

// 1. 获取P2P设备详细信息
const detailedInfo = await wifiP2p.getP2pDeviceInfo(deviceAddress);
console.info(`设备类型: ${detailedInfo.primaryDeviceType}`);
console.info(`支持WFD: ${detailedInfo.wfdInfo?.wfdEnabled}`);

// 2. Wi-Fi Display(WFD)支持
await wifiP2p.startWfd({
  deviceType: 'source', // 或'sink'
  audioSupport: true
});

// 3. 服务发现(Service Discovery)
await wifiP2p.startServiceDiscovery({
  serviceType: '_http._tcp',
  protocol: 'bonjour'
});

// 4. P2P节能模式
await wifiP2p.setP2pPowerSaveMode(true);

5.3 性能优化

HarmonyOS 6提供了更多性能调优选项:

// 设置发现参数
await wifiP2p.setDiscoveryConfig({
  scanInterval: 5000,    // 扫描间隔
  listenChannel: 6,      // 监听信道
  listenInterval: 500    // 监听间隔
});

// 设置连接参数
await wifiP2p.setConnectionConfig({
  intentValue: 10,       // Intent值
  timeout: 30000,        // 连接超时
  retryCount: 3          // 重试次数
});

六、总结

WiFi P2P为设备间直接通信提供了高效的解决方案,特别适合文件传输、投屏、多人游戏等场景。本文全面讲解了鸿蒙系统中P2P的核心要点:

核心要点回顾

  1. GO协商机制:理解Group Owner的角色分配逻辑
  2. 设备发现:合理控制发现时间和频率
  3. 连接管理:处理连接失败、重试、断开等场景
  4. 数据传输:通过Socket实现双向通信
  5. 互斥处理:注意WiFi连接与P2P的互斥关系

最佳实践建议

  • 封装统一的P2P管理类,简化使用
  • 实现完善的连接重试机制
  • 处理好GO和Client的角色差异
  • 做好版本适配和兼容性处理

下一步学习

  • 蓝牙BLE扫描与连接(下一篇文章)
  • 近场通信技术对比
  • 多设备协同方案
  • 无线投屏实现

WiFi P2P看似复杂,但掌握了核心原理后,实现起来其实并不困难。希望本文能帮助你建立起完整的知识体系,在实际开发中得心应手!

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。