目录

socket.sppReadAsync循环读取异常

问题现象

蓝牙spp连接成功后,调用socket.sppReadAsync,循环读取设备数据,只会成功读取一次,而后出现异常。问题代码如下:

import { socket } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';
let clientNumber = -1; // 入参clientNumber由sppAccept或sppConnect接口获取。
let buffer = new ArrayBuffer(1024);
let data = new Uint8Array(buffer);
let flag = 1;
while (flag) {
  try {
    socket.sppReadAsync(clientNumber).then((outBuffer: ArrayBuffer) => {
      buffer = outBuffer;
      if (buffer != null) {
        console.info(`sppRead success, data = ${JSON.stringify(buffer)}`);
      } else {
        console.error('sppRead error, data is null');
      }
    });
  } catch (err) {
    flag = 0;
    console.error(`startSppRead errCode: ${(err as BusinessError).code}, errMessage: ${(err as BusinessError).message}`);
  }
}

背景知识

问题定位

返回错误码401表示参数错误,删除while循环,就不会报错401,由此可得是多次调用导致的入参错误问题。socket.sppReadAsync是异步函数,在未等待执行结果后同时调用异步函数,并将同一个变量作为入参,导致数据资源存在竞争,导致入参异常。

分析结论

在执行异步函数时,应避免同时使用同一变量作为入参,否则可能存在资源访问异常情况,应该在异步函数执行完成后使用同一变量。

修改建议

socket.sppReadAsync该接口为异步接口,需要等异步回调结果返回后才能进行下一次调用。具体代码参考官方接口socket.sppReadAsync示例代码。

常见FAQ

Q:在经典蓝牙中,应用该如何感知蓝牙是否已经断连?

A:调用sppReadAsync方法来监听spp蓝牙是否断开连接,如果spp蓝牙断开的话,接口会返回2901054错误。

总结

在异步函数调用中,应该充分考虑入参是否存在资源竞争关系,是否存在明显的执行逻辑顺序。