报文接收端接收到的数据 带有C2

我方发送的报文,对方接收到后直接就是十六进制数据,但对方需要的是转为十六进制前的字符串;

错误采用方法:

    /**
     * 将十六进制转为字符串
     * 该方法 解析的报文 设备接收到后会出错 符号前会加C2
     * @param hex
     * @return
     */
    public static String convertHexToString(String hex){

        StringBuilder sb = new StringBuilder();
        StringBuilder temp = new StringBuilder();

        //49204c6f7665204a617661 split into two characters 49, 20, 4c...
        for( int i=0; i<hex.length()-1; i+=2 ){

            //grab the hex in pairs
            String output = hex.substring(i, (i + 2));
            //convert hex to decimal
            int decimal = Integer.parseInt(output, 16);
            //convert the decimal to character
            sb.append((char)decimal);
            temp.append(decimal);
        }

        return sb.toString();
    }

    /**
     * 字符串转十六进制
     * 与convertHexToString方法 互相转换 可以实现编码解码
     * @param str
     * @return
     */
    public static String convertStringToHex(String str){

        char[] chars = str.toCharArray();

        StringBuffer hex = new StringBuffer();
        for(int i = 0; i < chars.length; i++){
            hex.append(Integer.toHexString((int)chars[i]));
        }

        return hex.toString();
    }

调用方法:

session.write(IoBuffer.wrap(test.convertHexToString("01100064000A14000000010000000100010000000100010000000112BA").getBytes()));

结果:当出现特殊符号时,对方接收到转为十六进制后,其特殊符号前有C2标识符;
分析结果:
自测:使用convertHexToString转为字符串,再使用convertStringToHex方法转为十六进制;
推断:在调用session处,由于getBytes方法造成错误;将转字节数组的方法也放入转字符串的方法中;

正确方法:

  /**
     *该方法 为 将十六进制字符串转为 十六进制数组然后转为字符串
     */
    public static byte[] toByteArray(String hexString) {
        if (hexString == null || "".equals(hexString))
            throw new IllegalArgumentException("this hexString must not be empty");

        hexString = hexString.toLowerCase();
        final byte[] byteArray = new byte[hexString.length() / 2];
        int k = 0;
        for (int i = 0; i < byteArray.length; i++) {//因为是16进制,最多只会占用4位,转换成字节需要两个16进制的字符,高位在先
            byte high = (byte) (Character.digit(hexString.charAt(k), 16) & 0xff);
            byte low = (byte) (Character.digit(hexString.charAt(k + 1), 16) & 0xff);
            byteArray[i] = (byte) (high << 4 | low);
            k += 2;
        }
        return byteArray;
    }

调用:

session.write(IoBuffer.wrap(toByteArray("01100064000A14000000010000000100010000000100010000000112BA")));
<think>我们正在讨论gattlib库中的两个蓝牙写操作函数:`gattlib_write_without_response_char_by_uuid`和`gattlib_write_char_by_uuid`。这两个函数的主要区别在于是否要求对端设备(通常是BLE外设)发送响应。 ### 核心区别 1. **响应机制**: - `gattlib_write_char_by_uuid`:使用**Write Request**(写入请求),要求对端设备返回**Write Response**(写入响应)。这是一种可靠的写入方式,可以确保数据被对端正确接收[^1]。 - `gattlib_write_without_response_char_by_uuid`:使用**Write Command**(写入命令),不需要对端设备返回响应。这种方式更快但不可靠,适用于需要高速传输且可以容忍少量数据丢失的场景[^1]。 2. **数据长度限制**: - 带响应的写入(`gattlib_write_char_by_uuid`)受MTU(最大传输单元)限制,每次写入的数据长度不能超过MTU-3(默认20字节)[^1]。 - 无响应的写入(`gattlib_write_without_response_char_by_uuid`)同样受MTU限制,但通常可以一次写入更多数据(取决于具体实现)[^1]。 3. **可靠性**: - 带响应的写入:如果对端设备返回错误(如属性不可写),该函数会返回错误码。 - 无响应的写入:无法得知数据是否成功写入,即使对端设备不可用也不会返回错误。 4. **传输速度**: - 无响应的写入速度更快,因为它不需要等待对端响应。 - 带响应的写入速度较慢,但更可靠。 ### 函数原型 ```c // 带响应的写入 int gattlib_write_char_by_uuid(gatt_connection_t* connection, uuid_t* uuid, const void* buffer, size_t len); // 无响应的写入 int gattlib_write_without_response_char_by_uuid(gatt_connection_t* connection, uuid_t* uuid, const void* buffer, size_t len); ``` ### 使用场景建议 | 场景 | 推荐函数 | |------|----------| | 需要确保数据可靠传输(如配置命令) | `gattlib_write_char_by_uuid` | | 高速数据传输(如传感器数据流) | `gattlib_write_without_response_char_by_uuid` | | 对端设备处理能力较弱 | `gattlib_write_without_response_char_by_uuid`(避免频繁响应) | | 需要检测写入错误 | `gattlib_write_char_by_uuid` | ### 性能影响 无响应的写入虽然速度快,但过度使用可能导致: - 数据包丢失率上升(尤其在信号干扰环境) - 对端设备缓冲区溢出(引发断连) ### 解决断连问题的实践 在用户之前遇到的“写几次就断连”问题中,**无响应的写入**可能是主要原因之一。解决方案包括: 1. **切换为带响应的写入**: ```c // 将无响应写入改为带响应写入 gattlib_write_char_by_uuid(conn, &char_uuid, data, data_len); ``` 2. **增加写入间隔**: ```c // 无响应写入时增加延迟 gattlib_write_without_response_char_by_uuid(conn, &char_uuid, data, data_len); usleep(20000); // 20ms延迟 ``` 3. **组合使用**: ```c // 关键数据用带响应写入,非关键数据用无响应写入 if(is_critical_data) { gattlib_write_char_by_uuid(...); } else { gattlib_write_without_response_char_by_uuid(...); } ``` ### 底层协议交互对比 以发送数据`0xA0, 0xB1, 0xC2`为例: - **带响应写入**: ``` Central -> Peripheral: ATT Write Request (Handle=0x000E, Value=A0B1C2) Peripheral -> Central: ATT Write Response ``` - **无响应写入**: ``` Central -> Peripheral: ATT Write Command (Handle=0x000E, Value=A0B1C2) (无返回数据) ``` > **注意**:无响应写入在协议层称为“写入命令”(Write Command),带响应写入称为“写入请求”(Write Request)[^1]。 ### 错误处理差异 - `gattlib_write_char_by_uuid` 可能返回的错误码: - `GATTLIB_NOT_FOUND`:特征值UUID不存在 - `GATTLIB_WRITE_NOT_PERMITTED`:属性不可写 - `GATTLIB_TIMEOUT`:等待响应超时 - `gattlib_write_without_response_char_by_uuid` 通常只返回: - `GATTLIB_SUCCESS`:数据已加入发送队列(不保证到达) - `GATTLIB_NOT_FOUND`:特征值UUID不存在 ### 最佳实践 1. **初始化时协商MTU**: ```c gattlib_set_mtu(conn, 150); // 提升单次写入数据量 ``` 2. **混合模式写入**: ```c // 首次写入使用带响应模式(确保连接稳定) gattlib_write_char_by_uuid(conn, &config_uuid, config_data, 2); // 后续流数据使用无响应模式 for(int i=0; i<100; i++) { gattlib_write_without_response_char_by_uuid(conn, &data_uuid, sensor_data[i], 20); usleep(10000); // 10ms间隔 } ``` 3. **监控连接状态**: ```c if(gattlib_get_rssi(conn) < -90) { // 信号弱时切换为带响应写入 gattlib_write_char_by_uuid(...); } ``` --- ### 相关问题 1. 如何在gattlib中读取特征值的属性权限? 2. gattlib的无响应写入失败时为什么不会返回错误? 3. BLE协议中MTU协商的具体过程是怎样的? 4. 如何通过gattlib实现长数据分包写入? 5. 带响应写入超时可能由哪些原因引起? > 引用说明: > [^1]: 蓝牙核心规范v5.2中定义了ATT协议的写入请求(Write Request)和写入命令(Write Command)机制,前者需要响应而后者不需要[^1]。</think>### gattlib库中两个蓝牙写操作函数的区别 在gattlib库中,`gattlib_write_without_response_char_by_uuid`和`gattlib_write_char_by_uuid`是两种核心的蓝牙数据写入方式,主要区别在于**数据可靠性和传输机制**: #### 1. 协议层差异(核心区别) - **`gattlib_write_char_by_uuid`** 使用**ATT Write Request**协议(带响应写入): - 客户端发送写入请求后,必须等待服务端的**Write Response**确认 - 数据可靠性高,确保每个数据包都被接收方确认 - 传输速度较慢(需等待往返时延RTT) - 协议流程: `Central → Write Request → Peripheral` `Central ← Write Response ← Peripheral` $$ T_{\text{total}} = T_{\text{transmit}} + 2 \times T_{\text{propagation}} $$ - **`gattlib_write_without_response_char_by_uuid`** 使用**ATT Write Command**协议(无响应写入): - 客户端发送数据后**不等待**任何确认 - 传输速度快(无等待时延) - 数据可能丢失(尤其在信号干扰时) - 协议流程: `Central → Write Command → Peripheral` (无响应) #### 2. 函数原型对比 ```c // 带响应写入(可靠模式) int gattlib_write_char_by_uuid( gatt_connection_t* connection, uuid_t* uuid, // 目标特征值的UUID const void* buffer, // 写入数据缓冲区 size_t len // 数据长度 ); // 无响应写入(高速模式) int gattlib_write_without_response_char_by_uuid( gatt_connection_t* connection, uuid_t* uuid, // 目标特征值的UUID const void* buffer, // 写入数据缓冲区 size_t len // 数据长度 ); ``` #### 3. 关键特性对比表 | 特性 | 带响应写入 (`write_char_by_uuid`) | 无响应写入 (`write_without_response`) | |---------------------|-----------------------------------|---------------------------------------| | **数据可靠性** | 高(有确认机制)[^1] | 低(无确认) | | **传输速度** | 较慢(受RTT限制) | 快(无等待) | | **数据包丢失处理** | 自动重传 | 无重传 | | **适用场景** | 关键指令传输(如设备控制) | 流式数据传输(如传感器上报) | | **MTU限制** | 受协商MTU约束 | 受协商MTU约束 | | **资源消耗** | 较高(需维护确认状态) | 较低 | #### 4. 实际应用场景 - **使用带响应写入**的场景: ```c // 发送关键配置命令(必须确保到达) uint8_t config_cmd[] = {0x01, 0xA0, 0xFF}; ret = gattlib_write_char_by_uuid(conn, &config_uuid, config_cmd, sizeof(config_cmd)); if(ret != GATTLIB_SUCCESS) { // 处理写入失败(如重试逻辑) } ``` - **使用无响应写入**的场景: ```c // 高速传输传感器数据(容忍少量丢失) while(sensor_active) { get_sensor_data(buffer); gattlib_write_without_response_char_by_uuid(conn, &sensor_uuid, buffer, DATA_LEN); usleep(10000); // 10ms间隔防止过载 } ``` #### 5. 解决断连问题的选择建议 若您遇到**多次写入后断连**的问题,优先考虑: 1. **关键控制指令** → 使用带响应写入(确保可靠性) 2. **高速数据流** → 使用无响应写入+延迟控制: ```c // 解决方案:无响应写入+延迟 #define SAFE_WRITE_DELAY 20000 // 20ms void safe_write_without_response(...) { gattlib_write_without_response_char_by_uuid(...); usleep(SAFE_WRITE_DELAY); // 防止缓冲区溢出 } ``` 3. **混合模式**: ```c // 首次写入使用带响应模式建立可靠连接 gattlib_write_char_by_uuid(conn, &init_uuid, handshake, 3); // 后续数据流使用无响应模式 for(int i=0; i<100; i++) { safe_write_without_response(...); } ``` #### 6. 底层协议细节 两种写入方式在ATT层的行为差异: ```mermaid sequenceDiagram participant Central as 中央设备(主机) participant Peripheral as 外设(从机) %% 带响应写入流程 Central->>Peripheral: ATT Write Request (Opcode=0x12) Note right of Peripheral: 处理写入请求 Peripheral-->>Central: ATT Write Response (Opcode=0x13) %% 无响应写入流程 Central->>Peripheral: ATT Write Command (Opcode=0x52) Note right of Peripheral: 处理但不响应 ``` > ⚠️ **注意**:无响应写入虽然高效,但连续快速调用可能导致: > - 外设缓冲区溢出 > - 蓝牙协议栈崩溃 > - HCI层超时断连(表现为`org.bluez.Error.Failed`错误) --- ### 相关问题 1. 如何检测gattlib写入操作是否成功? 2. 无响应写入模式下如何确保数据完整性? 3. gattlib库中MTU协商失败该如何处理? 4. 蓝牙BLE协议中Write Request和Write Command的报文结构有何区别? 5. 如何通过Wireshark捕获并分析gattlib的蓝牙通信数据? > 引用说明: > [^1]: 蓝牙核心规范v5.2中定义了ATT协议的Write Request和Write Command机制,前者需要响应而后者不需要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值