文章目录

每日一句正能量
“别为不值得的事过度消耗自己,多聚焦自身成长。”
我们的心理能量是有限的,花费在纠结、悔恨、与他人纠缠上,便无暇灌溉自己。学会识别并远离“不值得的事”,是一种需要刻意练习的自我保护。
一、前言:从蓝牙到 WiFi P2P 的能力跃迁
在前三篇文章中,我们系统探讨了 BLE 低功耗蓝牙的扫描连接、数据传输与功耗优化。BLE 在穿戴设备、传感器等低功耗场景中表现优异,但其传输速率(≤ 3 Mbps)和有效距离(< 10 米)在面对大文件传输、高清投屏、多人游戏联机等高带宽需求时显得力不从心。
WiFi P2P(Wi-Fi Direct,又称 Wi-Fi 点对点)正是填补这一能力空白的关键技术。它允许 WiFi 设备无需通过路由器/AP 即可直接建立高速连接,最大传输速率可达 250 Mbps,传输距离最远 200 米,同时支持 WPA2 加密保障通信安全。cite🛠web_search:17#1:~:text=传输性能:在传输速度与传输距离方面比蓝牙有大幅度提升,最大传输距离可达 200 米,最大传输速度为 250Mbps
本文将聚焦 HarmonyOS 环境下 WiFi P2P 的完整开发链路,从权限申请、设备发现、P2P 连接、群组管理到 Socket 高速数据传输,提供一套可直接落地的工程化方案。
二、WiFi P2P 技术架构与核心概念
2.1 WiFi P2P 基本原理
WiFi P2P 由 Wi-Fi 联盟定义,其核心思想是让两个 WiFi 设备像蓝牙一样直接"对话",但享受 WiFi 级别的带宽。连接建立后,两台设备会自动协商出一个 Group Owner(GO,群组拥有者,承担类似 AP 的角色)和一个或多个 Group Client(GC,群组成员),形成一个小型的 WiFi 直连网络。允许无线网络中的设备无需通过无线路由器即可相互连接,以点对点的方式直接与另一个 WiFi 设备连线。
图 1:HarmonyOS WiFi P2P 整体架构与通信流程
2.2 GO 与 GC 角色协商
WiFi P2P 连接建立后,设备间会通过 GO Negotiation 过程协商谁当 GO、谁当 GC:
- Group Owner (GO):承担 SoftAP 角色,分配 IP 地址,其他设备连接它。GO 会暴露一个
goIpAddress,供 GC 连接。 - Group Client (GC):连接 GO,获取 IP 地址后通过 GO 的 IP 进行 Socket 通信。
关键注意:GC 知道 GO 的 IP 地址,但 GO 不知道 GC 的 IP。因此 Socket 编程的标准模式是 GO 做 Server,GC 做 Client。GC可以知道GO的地址,而GO是不知道GC的地址的。因此,一般的Socket编程思路是,GO做Server端,GC做Client端
三、开发环境准备与权限配置
3.1 模块权限声明
在 module.json5 中声明 WiFi P2P 相关权限:
{
"module": {
"name": "entry",
"type": "entry",
"requestPermissions": [
{
"name": "ohos.permission.GET_WIFI_INFO",
"reason": "$string:get_wifi_info_reason"
},
{
"name": "ohos.permission.SET_WIFI_INFO",
"reason": "$string:set_wifi_info_reason"
},
{
"name": "ohos.permission.GET_WIFI_PEERS_MAC",
"reason": "$string:get_peers_mac_reason"
},
{
"name": "ohos.permission.INTERNET",
"reason": "$string:internet_reason"
}
]
}
}
权限说明:
GET_WIFI_INFO和SET_WIFI_INFO是 P2P 发现与连接的基础权限;GET_WIFI_PEERS_MAC用于获取对端设备的 MAC 地址;INTERNET用于 Socket 通信。
3.2 动态权限申请
import { abilityAccessCtrl, common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
async function requestWiFiPermissions(): Promise<boolean> {
const context = getContext() as common.UIAbilityContext;
const atManager = abilityAccessCtrl.createAtManager();
try {
const grantStatus = await atManager.requestPermissionsFromUser(context, [
'ohos.permission.GET_WIFI_INFO',
'ohos.permission.SET_WIFI_INFO',
'ohos.permission.GET_WIFI_PEERS_MAC'
]);
return grantStatus.authResults.every(result => result === 0);
} catch (err) {
console.error('权限申请失败:', (err as BusinessError).message);
return false;
}
}
四、P2P 设备发现
4.1 注册发现状态监听
设备发现是 P2P 连接的第一步。HarmonyOS 通过事件回调机制通知发现状态变化:
import { wifiManager } from '@kit.ConnectivityKit';
import { promptAction } from '@kit.ArkUI';
class P2PDeviceDiscovery {
private peerDevices: Array<wifiManager.WifiP2pDevice> = [];
private isDiscovering: boolean = false;
aboutToAppear(): void {
// 注册发现设备状态监听
wifiManager.on('p2pDiscoveryChange', this.onDiscoveryChange);
// 注册设备列表变化监听
wifiManager.on('p2pDeviceChange', this.onDeviceChange);
}
aboutToDisappear(): void {
// 注销所有监听,防止内存泄漏
wifiManager.off('p2pDiscoveryChange', this.onDiscoveryChange);
wifiManager.off('p2pDeviceChange', this.onDeviceChange);
}
/** 发现状态变化回调: 0=初始, 1=发现成功 */
private onDiscoveryChange = (result: number): void => {
this.isDiscovering = result === 1;
promptAction.showToast({
message: result === 1 ? 'P2P 发现服务已启动' : 'P2P 发现服务已停止',
duration: 2000
});
};
/** 设备列表变化回调 */
private onDeviceChange = (result: Array<wifiManager.WifiP2pDevice>): void => {
this.peerDevices = result;
console.info(`[P2PDeviceDiscovery] 发现 ${result.length} 个设备`);
result.forEach(device => {
console.info(` 设备: ${device.deviceName}, MAC: ${device.deviceAddress}`);
});
};
}
4.2 启动与停止设备发现
/** 开始发现附近 P2P 设备 */
startDiscovery(): void {
try {
wifiManager.startDiscoverDevices();
console.info('[P2PDeviceDiscovery] P2P 设备发现已启动');
} catch (error) {
console.error('[P2PDeviceDiscovery] 启动发现失败:', JSON.stringify(error));
}
}
/** 停止设备发现 */
stopDiscovery(): void {
try {
wifiManager.stopDiscoverDevices();
console.info('[P2PDeviceDiscovery] P2P 设备发现已停止');
} catch (error) {
console.error('[P2PDeviceDiscovery] 停止发现失败:', JSON.stringify(error));
}
}
/** 获取当前发现的对端设备列表 */
async getPeerDeviceList(): Promise<Array<wifiManager.WifiP2pDevice>> {
return new Promise((resolve, reject) => {
wifiManager.getP2pPeerDevices((err, data) => {
if (err) {
console.error('[P2PDeviceDiscovery] 获取设备列表失败');
reject(err);
return;
}
console.info('[P2PDeviceDiscovery] 获取设备列表:', JSON.stringify(data));
this.peerDevices = data;
resolve(data);
});
});
}
发现超时策略:P2P 设备发现通常持续 120 秒后会自动停止,建议设置应用层超时(如 30 秒)主动停止,避免不必要的功耗。
五、P2P 连接与群组管理
5.1 注册连接状态监听
class P2PConnectionManager {
private connectionState: number = 0; // 0=断开, 1=连接
private groupInfo: wifiManager.WifiP2pGroupInfo | null = null;
private linkedInfo: wifiManager.WifiP2pLinkedInfo | null = null;
aboutToAppear(): void {
// 注册 P2P 连接状态变化监听
wifiManager.on('p2pConnectionChange', this.onConnectionChange);
// 注册 P2P 群组状态变化监听
wifiManager.on('p2pGroupChange', this.onGroupChange);
}
aboutToDisappear(): void {
wifiManager.off('p2pConnectionChange', this.onConnectionChange);
wifiManager.off('p2pGroupChange', this.onGroupChange);
}
/** 连接状态变化回调 */
private onConnectionChange = (result: wifiManager.WifiP2pLinkedInfo): void => {
this.linkedInfo = result;
this.connectionState = result.connectState;
console.info(`[P2PConnectionManager] 连接状态: ${result.connectState === 1 ? '已连接' : '已断开'}`);
if (result.connectState === 1) {
// 连接成功,获取群组信息
this.fetchGroupInfo();
}
};
/** 群组状态变化回调 */
private onGroupChange = (result: wifiManager.WifiP2pGroupInfo): void => {
this.groupInfo = result;
console.info(`[P2PConnectionManager] 群组变化: ${JSON.stringify(result)}`);
};
}
5.2 建立 P2P 连接
/** 连接到指定 P2P 设备 */
async connectToDevice(device: wifiManager.WifiP2pDevice): Promise<boolean> {
const config: wifiManager.WifiP2PConfig = {
deviceAddress: device.deviceAddress,
deviceAddressType: device.deviceAddressType,
netId: 0,
passphrase: '',
groupName: '',
goBand: 0
};
try {
wifiManager.p2pConnect(config);
console.info(`[P2PConnectionManager] 正在连接设备: ${device.deviceName}`);
return true;
} catch (error) {
console.error('[P2PConnectionManager] 连接失败:', JSON.stringify(error));
return false;
}
}
/** 获取当前群组信息(含 GO IP 地址) */
private async fetchGroupInfo(): Promise<void> {
return new Promise((resolve, reject) => {
wifiManager.getCurrentGroup((err, data) => {
if (err) {
console.error('[P2PConnectionManager] 获取群组信息失败');
reject(err);
return;
}
this.groupInfo = data;
console.info(`[P2PConnectionManager] 群组信息: ${JSON.stringify(data)}`);
console.info(`[P2PConnectionManager] GO IP 地址: ${data.goIpAddress}`);
resolve();
});
});
}
/** 断开 P2P 连接并移除群组 */
async disconnect(): Promise<void> {
try {
wifiManager.p2pDisConnect();
console.info('[P2PConnectionManager] P2P 连接已断开');
} catch (error) {
console.error('[P2PConnectionManager] 断开连接失败:', JSON.stringify(error));
}
}
图 2:WiFi P2P 设备发现与连接状态机
六、Socket 高速数据传输
P2P 连接建立并获取 GO 的 IP 地址后,即可通过标准 Socket 进行高速数据传输。以下是 GO 作为 Server、GC 作为 Client 的完整实现。
6.1 Group Owner 端(Server)
import { socket } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';
class P2PServer {
private serverSocket: socket.TCPSocketServer | null = null;
private connections: Array<socket.TCPSocketConnection> = [];
private readonly SERVER_PORT = 8988;
/** 启动 P2P 服务端 */
async startServer(onMessage: (data: string) => void): Promise<void> {
this.serverSocket = socket.constructTCPSocketServerInstance();
const bindAddress: socket.NetAddress = {
address: '0.0.0.0', // 监听所有接口
port: this.SERVER_PORT
};
await this.serverSocket.bind(bindAddress);
console.info(`[P2PServer] 服务端已启动,监听端口: ${this.SERVER_PORT}`);
// 监听客户端连接
this.serverSocket.on('connect', (connection: socket.TCPSocketConnection) => {
console.info(`[P2PServer] 客户端已连接: ${connection.remoteAddress?.address}`);
this.connections.push(connection);
this.setupConnection(connection, onMessage);
});
await this.serverSocket.listen(5);
}
private setupConnection(connection: socket.TCPSocketConnection, onMessage: (data: string) => void): void {
// 接收数据
connection.on('message', (msg: socket.SocketMessageInfo) => {
const received = bufferToString(msg.message);
console.info(`[P2PServer] 收到消息: ${received}`);
onMessage(received);
});
// 连接关闭
connection.on('close', () => {
console.info('[P2PServer] 客户端连接已关闭');
this.connections = this.connections.filter(c => c !== connection);
});
}
/** 向所有客户端广播消息 */
async broadcast(message: string): Promise<void> {
const data = stringToBuffer(message);
for (const conn of this.connections) {
const sendOptions: socket.TCPSendOptions = {
data: data,
encoding: 'utf-8'
};
await conn.send(sendOptions);
}
console.info(`[P2PServer] 广播消息: ${message}`);
}
/** 停止服务端 */
async stopServer(): Promise<void> {
for (const conn of this.connections) {
await conn.close();
}
this.connections = [];
await this.serverSocket?.close();
console.info('[P2PServer] 服务端已停止');
}
}
6.2 Group Client 端(Client)
class P2PClient {
private clientSocket: socket.TCPSocket | null = null;
private readonly SERVER_PORT = 8988;
/** 连接到 GO 的服务端 */
async connectToServer(goIpAddress: string): Promise<boolean> {
this.clientSocket = socket.constructTCPSocketInstance();
const serverAddress: socket.NetAddress = {
address: goIpAddress,
port: this.SERVER_PORT
};
try {
await this.clientSocket.connect({
address: serverAddress,
timeout: 10000 // 10秒超时
});
console.info(`[P2PClient] 已连接到服务端: ${goIpAddress}:${this.SERVER_PORT}`);
return true;
} catch (err) {
console.error('[P2PClient] 连接服务端失败:', (err as BusinessError).message);
return false;
}
}
/** 发送消息到服务端 */
async sendMessage(message: string): Promise<void> {
if (!this.clientSocket) return;
const sendOptions: socket.TCPSendOptions = {
data: stringToBuffer(message),
encoding: 'utf-8'
};
await this.clientSocket.send(sendOptions);
console.info(`[P2PClient] 发送消息: ${message}`);
}
/** 监听服务端消息 */
onMessage(callback: (data: string) => void): void {
this.clientSocket?.on('message', (msg: socket.SocketMessageInfo) => {
const received = bufferToString(msg.message);
console.info(`[P2PClient] 收到消息: ${received}`);
callback(received);
});
}
/** 断开连接 */
async disconnect(): Promise<void> {
await this.clientSocket?.close();
console.info('[P2PClient] 已断开连接');
}
}
// 工具函数
function stringToBuffer(str: string): ArrayBuffer {
const encoder = new TextEncoder();
return encoder.encode(str).buffer;
}
function bufferToString(buffer: ArrayBuffer): string {
const decoder = new TextDecoder('utf-8');
return decoder.decode(buffer);
}
6.3 大文件传输实现
WiFi P2P 的核心优势在于大文件高速传输。以下是一个基于 TCP 的文件传输实现:
class P2PFileTransfer {
private readonly CHUNK_SIZE = 65536; // 64KB 分片
/** 发送文件(Client 端调用) */
async sendFile(filePath: string, onProgress?: (sent: number, total: number) => void): Promise<void> {
const file = fs.openSync(filePath, fs.OpenMode.READ_ONLY);
const stat = fs.statSync(filePath);
const totalSize = stat.size;
// 发送文件元数据
const metadata = JSON.stringify({
type: 'FILE_START',
fileName: filePath.split('/').pop(),
fileSize: totalSize
});
await this.sendMessage(metadata);
// 分片发送文件内容
let sent = 0;
const buffer = new ArrayBuffer(this.CHUNK_SIZE);
while (sent < totalSize) {
const readLen = fs.readSync(file.fd, buffer, { offset: 0, length: this.CHUNK_SIZE });
await this.sendRawData(buffer.slice(0, readLen));
sent += readLen;
onProgress?.(sent, totalSize);
}
fs.closeSync(file);
// 发送结束标记
await this.sendMessage(JSON.stringify({ type: 'FILE_END' }));
console.info(`[P2PFileTransfer] 文件发送完成: ${sent} 字节`);
}
/** 接收文件(Server 端回调中处理) */
private receivedChunks: Array<ArrayBuffer> = [];
private expectedFileSize: number = 0;
handleIncomingData(data: string | ArrayBuffer): void {
if (typeof data === 'string') {
const msg = JSON.parse(data);
if (msg.type === 'FILE_START') {
this.expectedFileSize = msg.fileSize;
this.receivedChunks = [];
console.info(`[P2PFileTransfer] 开始接收文件: ${msg.fileName}, 大小: ${msg.fileSize}`);
} else if (msg.type === 'FILE_END') {
this.saveReceivedFile();
}
} else {
this.receivedChunks.push(data);
}
}
private saveReceivedFile(): void {
const totalSize = this.receivedChunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);
const merged = new Uint8Array(totalSize);
let offset = 0;
for (const chunk of this.receivedChunks) {
merged.set(new Uint8Array(chunk), offset);
offset += chunk.byteLength;
}
// 保存到本地
const savePath = getContext().filesDir + '/received_file.bin';
const file = fs.openSync(savePath, fs.OpenMode.WRITE_ONLY | fs.OpenMode.CREATE);
fs.writeSync(file.fd, merged.buffer);
fs.closeSync(file);
console.info(`[P2PFileTransfer] 文件接收完成,保存至: ${savePath}`);
}
}
七、近场通信技术对比与选型
图 3:HarmonyOS 近场通信技术对比与 WiFi P2P 应用场景
7.1 混合传输模式:NFC/蓝牙握手 + WiFi P2P 传数据
在实际产品中,单一通信技术往往无法满足所有需求。最佳实践是组合使用:
- NFC 触碰握手:交换设备标识、会话密钥、文件元数据(< 1KB)。
- 蓝牙辅助发现:在 NFC 范围外时,通过 BLE 广播设备存在。
- WiFi P2P 高速传输:建立 P2P 连接后传输大文件主体。
- 结果验证:传输完成后通过原通道验证文件完整性。NFC 握手:通过 NFC 交换设备信息、会话密钥和文件元数据…WLAN Direct 传输:利用 @ohos.wifi.p2p 建立高速通道,传输文件主体。
八、完整 ArkUI 界面示例
以下是一个完整的 WiFi P2P 文件传输 UI 页面:
import { wifiManager } from '@kit.ConnectivityKit';
import { promptAction } from '@kit.ArkUI';
interface P2PDeviceItem {
deviceName: string;
deviceAddress: string;
isConnected: boolean;
}
@Entry
@Component
struct WiFiP2PPage {
@State deviceList: Array<P2PDeviceItem> = [];
@State isDiscovering: boolean = false;
@State isConnected: boolean = false;
@State goIpAddress: string = '';
@State logText: string = '';
private discovery: P2PDeviceDiscovery = new P2PDeviceDiscovery();
private connection: P2PConnectionManager = new P2PConnectionManager();
private server: P2PServer = new P2PServer();
private client: P2PClient = new P2PClient();
aboutToAppear() {
requestWiFiPermissions().then(granted => {
if (!granted) {
promptAction.showToast({ message: '需要 WiFi 权限才能使用 P2P 功能' });
}
});
}
/** 开始/停止发现 */
toggleDiscovery() {
if (this.isDiscovering) {
this.discovery.stopDiscovery();
this.isDiscovering = false;
} else {
this.deviceList = [];
this.isDiscovering = true;
this.discovery.startDiscovery();
// 5秒后自动获取设备列表
setTimeout(async () => {
const devices = await this.discovery.getPeerDeviceList();
this.deviceList = devices.map(d => ({
deviceName: d.deviceName || '未知设备',
deviceAddress: d.deviceAddress,
isConnected: false
}));
}, 3000);
}
}
/** 连接设备 */
async connectDevice(device: P2PDeviceItem) {
this.appendLog(`正在连接 ${device.deviceName}...`);
const targetDevice = this.discovery['peerDevices'].find(
d => d.deviceAddress === device.deviceAddress
);
if (targetDevice) {
await this.connection.connectToDevice(targetDevice);
}
}
appendLog(msg: string) {
const time = new Date().toLocaleTimeString();
this.logText = `[${time}] ${msg}\n${this.logText}`;
}
build() {
Column({ space: 12 }) {
Text('WiFi P2P 文件传输')
.fontSize(22).fontWeight(FontWeight.Bold).fontColor('#303133')
Button(this.isDiscovering ? '停止发现' : '发现设备')
.width('90%').height(48)
.fontSize(16).fontColor(Color.White)
.backgroundColor(this.isDiscovering ? '#F56C6C' : '#409EFF')
.onClick(() => this.toggleDiscovery())
List({ space: 8 }) {
ForEach(this.deviceList, (item: P2PDeviceItem) => {
ListItem() {
Row() {
Column() {
Text(item.deviceName)
.fontSize(15).fontWeight(FontWeight.Medium).fontColor('#303133')
Text(`MAC: ${item.deviceAddress}`)
.fontSize(12).fontColor('#909399').margin({ top: 4 })
}
.alignItems(HorizontalAlign.Start).layoutWeight(1)
Button('连接')
.width(72).height(36).fontSize(13)
.backgroundColor('#67C23A')
.onClick(() => this.connectDevice(item))
}
.width('100%').padding(12)
.backgroundColor('#F5F7FA').borderRadius(8)
}
}, (item: P2PDeviceItem) => item.deviceAddress)
}
.width('90%').layoutWeight(1).padding({ top: 8 })
Column() {
Text('运行日志').fontSize(14).fontWeight(FontWeight.Bold).fontColor('#606266').margin({ bottom: 8 })
Text(this.logText).fontSize(11).fontColor('#909399')
.width('100%').maxLines(8)
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
.width('90%').height(160).padding(12)
.backgroundColor('#FAFAFA').borderRadius(8)
.margin({ bottom: 16 })
}
.width('100%').height('100%').backgroundColor(Color.White)
}
}
九、常见问题与排查
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 无法发现设备 | WLAN 未开启 / 权限未授予 | 检查 GET_WIFI_INFO 权限;确认设备 WLAN 开关已打开 |
| 连接失败 | 对端设备未开启 P2P 发现 | 确保两台设备同时处于发现状态 |
| Socket 连接超时 | GO IP 地址获取失败 | 确认 getCurrentGroup 在连接成功后调用;检查防火墙 |
| 传输速率远低于 250Mbps | 设备距离过远 / 障碍物遮挡 | 缩短设备距离;避免金属遮挡;协商 5GHz 频段 |
| 连接频繁断开 | Supervision Timeout 过短 | 延长超时时间;检查信号强度 RSSI |
十、总结
本文系统讲解了 HarmonyOS 环境下 WiFi P2P(Wi-Fi Direct)的完整开发链路:
- 技术架构:理解 GO/GC 角色协商、WiFi P2P 直连无需路由器的核心优势;
- 设备发现:通过
startDiscoverDevices与事件监听实现设备扫描与列表获取; - P2P 连接:
p2pConnect建立连接,getCurrentGroup获取 GO IP 地址; - Socket 通信:GO 作为 TCP Server、GC 作为 TCP Client 的标准模式;
- 大文件传输:64KB 分片传输 + 元数据协议,实现稳定高速的文件互传;
- 技术选型:BLE vs WiFi P2P vs 传统 WiFi 的对比与混合传输模式最佳实践。
将本文的 WiFi P2P 高速传输能力与前面 BLE 三部曲的低功耗连接能力相结合,即可构建"BLE 发现握手 + WiFi P2P 高速传输"的鸿蒙近场通信完整解决方案,覆盖从微安级传感器到百兆级文件传输的全场景需求。
转载自:https://blog.csdn.net/u014727709/article/details/163676811
欢迎 👍点赞✍评论⭐收藏,欢迎指正



2450

被折叠的 条评论
为什么被折叠?



