提升Android BLE蓝牙传输速度的技巧与方法
EDR 即Enhanced data rate,是蓝牙技术中增强速率的缩写,其特色是大大提高了蓝牙技术的数据传输速率,达到了2.1Mbps ,是目前蓝牙技术的三倍。因此除了可获得更稳定的音频流传送的更低的耗电量之外,还可充分利用带宽优势同时连接多个蓝牙设备。目前诸如多普达 710 等手机已经开始支持蓝牙EDR 技术。
Bluetooth2.0的规范中,EDR作为补充出现的,它正确定义了调变技术的改变,和额外的封包类型,这使它能够以3MBPS的速率传输.所以,我们通常看到的是"蓝牙核心规范2.0版本+ EDR"的说法。
实际情况是:目前并没有一项蓝牙应用的传输需要超过1MBPS.即使是高音质的立体声数据流,它必须使用次频宽编解码技术(Subband codec;SBC codec,最多也就需要345KBPS即可。
但是,由于蓝牙设备的日渐普及,用户可能会同时使用多个蓝牙设备,尤其是在电脑的环境中,可以有鼠标、键盘、耳机、手机、PDA、打印机等设备需要同时工作。EDR提供了额外的频宽给蓝牙射频,使所有的设备拥有令人满意的传输速率。
如果用户想要倾听高音质的立体音响效果,就需要345 kbps的数据传输率,而不是中等音质的传输率237 kbps。高音质的音讯串流会占用53%的频宽,加上鼠标和键盘所需的22%之频宽,只剩下25%的频宽,对需要重传(retransmission)的 情况,这是不够用的。而且,如果通讯干扰很严重时,则25%的频宽将更加不敷使用。
若改用EDR,则可以解决上述的问题。在EDR的通讯环境中,鼠标和键盘仍然维持11%的最大频宽消耗量,但是,高质量的音讯串流现在只会占用18%的频 宽,因此,频宽能剩下60%。即使在严重干扰的情况下,通讯效能仍然能够轻易地维持在可以接受的程度。这还可以为其它额外的应用提供足够的频宽,譬如:打 印档案、或同步传收数据(synchronizing data)。
EDR除了支持高音质的音频流以外,它也能协助降低功率的损耗。蓝牙射频所需要的功率大小,是由它处于工作模式(active mode)下的时间长度而定。由于EDR使数据传输率增加了3倍,因此蓝牙射频处于工作模式下的时间长度,如今只需要过去的1/3,而所需要的功率也只有 过去的1/3。
EDR可以100%和蓝牙1.2版兼容。向后兼容(backwards compatibility)是当初在开发EDR时,就一直强调的。蓝牙网络允许具有EDR功能的装置和具有标准传输率(1 Mbps)的装置混合共存。新的调变设计也能和标准传输率兼容,因此双方可以接收对方发射的讯号。这意味着在设计具有EDR功能的产品时,将不会比设计蓝 牙1.2版产品复杂。
来源:
英文的whatis
What is Bluetooth 2.0+EDR
Know-IT-All
- Roadmap boosts Bluetooth bandwidth A three-year roadmap for Bluetooth short-range ... (ComputerWeekly.com)
- Video: The Quore WiBrain UMPC review Quore has released a Wibrain portable computer ... (ComputerWeekly.com)
Bluetooth 2.0+EDR and Bluetooth 2.1+EDR are specifications for short-range wireless data exchange. Both Version 2.0 and 2.1 support EDR (Enhanced Data Rate), a faster PSKmodulation scheme capable of transmitting data 2 or 3 times faster than previous versions of Bluetooth.
Version 2.1+EDR is built to be more secure and make man-in-the-middle (eavesdropping) attacks more difficult. Connecting, which is called "pairing" is easier than in previous versions. In version 2, a Bluetooth device will make a connection automatically and all the end user has to do is confirm the connection. Version 2 also allows multiple Bluetooth connections at the same time.
A feature called Sniff Subrating extends battery life by reducing the active duty cycle of Bluetooth devices like keyboards and mice to improve battery life. Bluetooth hosts can specify maximum transmit and receive latencies so that low-power devices can know how often they must exit and re-enter "sniff mode." This can result in up to five times the battery life experienced by older low-power Bluetooth devices.
Specifications |
Bluetooth 1.0 |
Bluetooth 1.2 |
Bluetooth 2.0+EDR (enhanced data rate) |
Bluetooth 2.1+EDR (enhanced data rate) |
Bluetooth 3.0 HS (high speed) |
Transmission rate |
721 kbit/s |
721 kbit/s |
2.1 Mbits/s |
3 Mbits/s |
24 Mbit/s |
Adopted |
2002 |
2005 |
2004 |
2007 |
2009 |
Backward compatible |
yes |
yes |
yes |
yes |
|
Simple Secure Pairing |
yes |
yes |
yes |
yes |
|
Near Field Communication |
yes |
yes |
|||
Sniff Subrating |
yes |
yes |
|||
802.11 Protocol Adaptation Layer (PAL) |
yes |
||||
Standard PANrange |
|
|
10 meters (33 feet) |
10 meters (33 feet) |
10 meters (33 feet) |
推荐阅读
-
提高蓝牙速度的技巧与深度解析 - 包含iOS和Android的速度测试报告
-
理解 Android 中的传统蓝牙与蓝牙 5.1 的数据传输速度差异
-
提高Android设备蓝牙传输速度的方法
-
提升Android BLE蓝牙传输速度的技巧与方法
-
【Netty】「萌新入门」(七)ByteBuf 的性能优化-堆内存的分配和释放都是由 Java 虚拟机自动管理的,这意味着它们可以快速地被分配和释放,但是也会产生一些开销。 直接内存需要手动分配和释放,因为它由操作系统管理,这使得分配和释放的速度更快,但是也需要更多的系统资源。 另外,直接内存可以映射到本地文件中,这对于需要频繁读写文件的应用程序非常有用。 此外,直接内存还可以避免在使用 NIO 进行网络传输时发生数据拷贝的情况。在使用传统的 I/O 时,数据必须先从文件或网络中读取到堆内存中,然后再从堆内存中复制到直接缓冲区中,最后再通过 SocketChannel 发送到网络中。而使用直接缓冲区时,数据可以直接从文件或网络中读取到直接缓冲区中,并且可以直接从直接缓冲区中发送到网络中,避免了不必要的数据拷贝和内存分配。 通过 ByteBufAllocator.DEFAULT.directBuffer 方法来创建基于直接内存的 ByteBuf: ByteBuf directBuf = ByteBufAllocator.DEFAULT.directBuffer(16); 通过 ByteBufAllocator.DEFAULT.heapBuffer 方法来创建基于堆内存的 ByteBuf: ByteBuf heapBuf = ByteBufAllocator.DEFAULT.heapBuffer(16); 注意: 直接内存是一种特殊的内存分配方式,可以通过在堆外申请内存来避免 JVM 堆内存的限制,从而提高读写性能和降低 GC 压力。但是,直接内存的创建和销毁代价昂贵,因此需要慎重使用。 此外,由于直接内存不受 JVM 垃圾回收的管理,我们需要主动释放这部分内存,否则会造成内存泄漏。通常情况下,可以使用 ByteBuffer.clear 方法来释放直接内存中的数据,或者使用 ByteBuffer.cleaner 方法来手动释放直接内存空间。 测试代码: public static void testCreateByteBuf { ByteBuf buf = ByteBufAllocator.DEFAULT.buffer(16); System.out.println(buf.getClass); ByteBuf heapBuf = ByteBufAllocator.DEFAULT.heapBuffer(16); System.out.println(heapBuf.getClass); ByteBuf directBuf = ByteBufAllocator.DEFAULT.directBuffer(16); System.out.println(directBuf.getClass); } 运行结果: class io.netty.buffer.PooledUnsafeDirectByteBuf class io.netty.buffer.PooledUnsafeHeapByteBuf class io.netty.buffer.PooledUnsafeDirectByteBuf 池化技术 在 Netty 中,池化技术指的是通过对象池来重用已经创建的对象,从而避免了频繁地创建和销毁对象,这种技术可以提高系统的性能和可伸缩性。 通过设置 VM options,来决定池化功能是否开启: -Dio.netty.allocator.type={unpooled|pooled} 在 Netty 4.1 版本以后,非 Android 平台默认启用池化实现,Android 平台启用非池化实现; 这里我们使用非池化功能进行测试,依旧使用的是上面的测试代码 testCreateByteBuf,运行结果如下所示: class io.netty.buffer.UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeDirectByteBuf class io.netty.buffer.UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf class io.netty.buffer.UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeDirectByteBuf 可以看到,ByteBuf 类由 PooledUnsafeDirectByteBuf 变成了 UnpooledUnsafeDirectByteBuf; 在没有池化的情况下,每次使用都需要创建新的 ByteBuf 实例,这个操作会涉及到内存的分配和初始化,如果是直接内存则代价更为昂贵,而且频繁的内存分配也可能导致内存碎片问题,增加 GC 压力。 使用池化技术可以避免频繁内存分配带来的开销,并且重用池中的 ByteBuf 实例,减少了内存占用和内存碎片问题。另外,池化技术还可以采用类似 jemalloc 的内存分配算法,进一步提升分配效率。 在高并发环境下,池化技术的优点更加明显,因为内存的分配和释放都是比较耗时的操作,频繁的内存分配和释放会导致系统性能下降,甚至可能出现内存溢出的风险。使用池化技术可以将内存分配和释放的操作集中到预先分配的池中,从而有效地降低系统的内存开销和风险。 内存释放 当在 Netty 中使用 ByteBuf 来处理数据时,需要特别注意内存回收问题。 Netty 提供了不同类型的 ByteBuf 实现,包括堆内存(JVM 内存)实现 UnpooledHeapByteBuf 和堆外内存(直接内存)实现 UnpooledDirectByteBuf,以及池化技术实现的 PooledByteBuf 及其子类。 UnpooledHeapByteBuf:通过 Java 的垃圾回收机制来自动回收内存; UnpooledDirectByteBuf:由于 JVM 的垃圾回收机制无法管理这些内存,因此需要手动调用 release 方法来释放内存; PooledByteBuf:使用了池化机制,需要更复杂的规则来回收内存; 由于池化技术的特殊性质,释放 PooledByteBuf 对象所使用的内存并不是立即被回收的,而是被放入一个内存池中,待下次分配内存时再次使用。因此,释放 PooledByteBuf 对象的内存可能会延迟到后续的某个时间点。为了避免内存泄漏和占用过多内存,我们需要根据实际情况来设置池化技术的相关参数,以便及时回收内存; Netty 采用了引用计数法来控制 ByteBuf 对象的内存回收,在博文 「源码解析」ByteBuf 的引用计数机制 中将会通过解读源码的形式对 ByteBuf 的引用计数法进行深入理解; 每个 ByteBuf 对象被创建时,都会初始化为1,表示该对象的初始计数为1。 在使用 ByteBuf 对象过程中,如果当前 handler 已经使用完该对象,需要通过调用 release 方法将计数减1,当计数为0时,底层内存会被回收,该对象也就被销毁了。此时即使 ByteBuf 对象还在,其各个方法均无法正常使用。 但是,如果当前 handler 还需要继续使用该对象,可以通过调用 retain 方法将计数加1,这样即使其他 handler 已经调用了 release 方法,该对象的内存仍然不会被回收。这种机制可以有效地避免了内存泄漏和意外访问已经释放的内存的情况。 一般来说,应该尽可能地保证 retain 和 release 方法成对出现,以确保计数正确。