MTU (Maximum Transmission Unit) — to maksymalny rozmiar użytecznych danych w jednym pakiecie BLE, który może być przesłany między urządzeniami w ramach jednej transakcji GATT. W BLE Classic (4.x) MTU jest stałe na poziomie 23 bajtów, co wystarcza do małych odczytów czujników, ale nie do przesyłania plików lub aktualizacji OTA. Bluetooth Core Specification 4.2 (2014) wprowadziła procedurę MTU Size Request, umożliwiającą negocjację większego MTU — do 247 bajtów (BLE 5.0 — do 251 bajtów). Prawidłowa konfiguracja MTU to jeden z kluczowych czynników wydajności aplikacji BLE przesyłających duże ilości danych.
Najważniejsze
Maximum Transmission Unit (MTU) w kontekście BLE — to maksymalny rozmiar Application Protocol Data Unit (APDU), który urządzenie może przyjąć w jednym żądaniu GATT. MTU jest określane na poziomie ATT (Attribute Protocol) i zawiera nagłówek ATT (1 bajt) + dane użyteczne. Domyślnie wszystkie urządzenia BLE obsługują MTU 23 bajtów (23 = 1 bajt nagłówka ATT + 22 bajty danych).
MTU to nie fizyczny limit kanału radiowego, ale umowa między urządzeniami na poziomie GATT. Fizyczny rozmiar pakietu BLE w warstwie Link Layer może być większy (do 27 bajtów w BLE 4.0, do 257 bajtów w BLE 5.0 z Data Length Extension), ale warstwa GATT ogranicza, ile danych jest przesyłanych w jednej transakcji. Data Length Extension (DLE) — to osobny mechanizm w warstwie Link Layer, który zwiększa fizyczny pakiet do 251 bajtów i musi być negocjowany osobno.
Różnica między MTU a DLE: ATT MTU — ile danych jest przesyłanych w jednym żądaniu GATT, DLE — ile danych mieści się w jednym pakiecie Link Layer. Aby uzyskać maksymalną prędkość, należy negocjować oba parametry. Bez DLE nawet przy MTU 247 bajtów dane będą fragmentowane na kilka pakietów Link Layer po 27 bajtów, zmniejszając przepustowość.
MTU Size Request — procedura inicjowana przez Central po nawiązaniu połączenia GATT. Central wysyła MTU Request z podaniem swojej pojemności MTU (maksymalny rozmiar, jaki może przyjąć). Peripheral odpowiada MTU Response ze swoją wartością. Używane MTU to minimalna z dwóch wartości. Jeśli Central proponuje MTU 512, a Peripheral obsługuje tylko 128, połączenie będzie używać MTU 128.
import CoreBluetooth
// Żądanie maksymalnego MTU w iOS
func requestMTU(central: CBCentralManager,
peripheral: CBPeripheral) {
peripheral.maximumWriteValueLength(
for: .withoutResponse
)
// iOS automatycznie negocjuje MTU przy połączeniu
// MTU = 512 dla urządzeń BLE 5.0
let mtu = peripheral.maximumWriteValueLength(
for: .withResponse
)
print("Negocjowane MTU: " +
String(mtu))
}
Moment negocjacji: MTU Request powinien być wysłany po wykryciu usług (discoverServices), ale przed rozpoczęciem aktywnego przesyłania danych. W iOS Core Bluetooth automatycznie negocjuje MTU przy połączeniu — programista nie musi ręcznie wysyłać MTU Request. W Androidzie należy jawnie wywołać requestMTU. Po negocjacji MTU pozostaje stałe dla danego połączenia — ponowna negocjacja jest niemożliwa bez rozłączenia i ponownego połączenia.
ATT (Attribute Protocol) — protokół, na którym zbudowany jest GATT. Pakiet ATT ma maksymalny rozmiar 257 bajtów (ATT_MTU-1). Z tego 1 bajt to Opcode (typ operacji), 1 bajt to Handle, do 255 bajtów to Value. Zatem maksymalne MTU dozwolone przez specyfikację ATT to 257 bajtów (w praktyce używa się do 251 bajtów, ponieważ część pól pomocniczych i tak jest potrzebna).
Do wysyłania danych większych niż MTU używa się fragmentacji na poziomie aplikacji. Programista sam dzieli dane na kawałki o rozmiarze ≤ MTU i wysyła je sekwencyjnie. Każdy kawałek jest formalnie osobnym żądaniem GATT Write Request. Strona odbierająca składa kawałki w jeden bufor. Wbudowanej obsługi fragmentacji w GATT nie ma — to zadanie programisty.
| Wersja BLE | Maks. MTU | Maks. DLE | Limit ATT MTU |
|---|---|---|---|
| BLE 4.0 / 4.1 | 23 bajty | 27 bajtów | ATT stały |
| BLE 4.2 | 247 bajtów | 251 bajtów | 257 bajtów |
| BLE 5.0 | 251 bajtów | 251 bajtów | 257 bajtów |
| Android + iOS | 512 / 517 | 251 bajtów | Przekroczenie ATT |
Ciekawostka: iOS i Android żądają MTU odpowiednio 512 i 517 bajtów, ale ta wartość przekracza limit ATT. W praktyce stos BLE automatycznie fragmentuje takie dane, wysyłając je jako kilka sekwencyjnych żądań GATT po maksymalnie 251 bajtów. Dla programisty różnica jest niezauważalna — writeValue działa z dowolnym rozmiarem do 512 bajtów w iOS.
Rozmiar MTU bezpośrednio wpływa na przepustowość połączenia BLE. Przy MTU 23 bajtów maksymalna użyteczna szybkość transmisji wynosi około 7–10 KB/s w idealnych warunkach. Zwiększenie MTU do 247 bajtów podnosi prędkość do 60–90 KB/s (z DLE i optymalnym connection interval). Jest to szczególnie ważne dla aplikacji przesyłających obrazy, fragmenty audio lub logi.
Wydajność transmisji BLE zależy od trzech czynników: MTU (ile danych w jednym żądaniu ATT), connection interval (jak często odbywają się zdarzenia wymiany) i DLE (ile danych w jednym pakiecie Link Layer). Optymalna konfiguracja dla maksymalnej prędkości: MTU = 247, DLE = 251, connection interval = 7.5 ms (wartość minimalna).
Według danych Bluetooth SIG White Paper (2023), zwiększenie MTU z 23 do 247 bajtów przy connection interval 30 ms zwiększa przepustowość z 8 KB/s do 42 KB/s — wzrost 5-krotny. Przy connection interval 7.5 ms przepustowość osiąga 88 KB/s. Dla aplikacji niewymagających dużej prędkości (czujniki temperatury, beacony BLE) standardowe MTU 23 bajtów pozostaje wystarczające.
iOS Core Bluetooth automatycznie negocjuje MTU przy połączeniu z Peripheral. Programista może sprawdzić bieżące MTU przez maximumWriteValueLength, ale nie może go ustawić ręcznie. iOS używa MTU do 512 bajtów dla urządzeń BLE 5.0 i do 247 dla BLE 4.2. Do zapisu dużych ilości danych używaj writeType: .withResponse dla gwarantowanej dostawy.
// Żądanie MTU na Androidzie (Kotlin)
val bluetoothGatt: BluetoothGatt = ...
// Żądanie MTU 517 bajtów
bluetoothGatt.requestMtu(517)
// Obsługa wyniku w callbacku
override fun onMtuChanged(
gatt: BluetoothGatt,
mtu: Int,
status: Int
) {
if (status == BluetoothGatt.GATT_SUCCESS) {
println("MTU negotiated: $mtu")
}
}
Android udostępnia BluetoothGatt.requestMtu(int), który pozwala zażądać dowolnego MTU do 517 bajtów. Rzeczywiste MTU jest określane przez urządzenie peryferyjne — jeśli obsługuje tylko 23 bajty, Android zwróci MTU 23. Do określenia bieżącego MTU użyj gatt.requestMtu(0) — zwróci bieżącą wartość bez próby zmiany. Android 12+ obsługuje automatyczną negocjację MTU przy połączeniu przez TRANSPORT_LE.
Frameworki międzyplatformowe (Flutter, React Native) zazwyczaj udostępniają API do requestMTU. W bibliotece FlutterBlue Plus MTU jest ustawiane jako parametr połączenia. W RxAndroidBle — przez metodę requestMtu. Zaleca się zawsze negocjować maksymalne MTU zaraz po wykryciu usług, przed rozpoczęciem przesyłania danych, aby uniknąć fragmentacji na poziomie aplikacji.
OTA (Over-The-Air) aktualizacje oprogramowania — najbardziej wymagający względem MTU scenariusz w BLE. Typowy rozmiar oprogramowania urządzenia IoT to 100–500 KB. Przy MTU 23 bajtów i connection interval 30 ms transmisja 100 KB zajmuje około 2–3 minut. Przy MTU 247 bajtów i DLE 251 bajtów — 20–40 sekund. A przy MTU 512 bajtów (iOS) — 10–15 sekund.
Proces aktualizacji OTA zazwyczaj obejmuje: fragmentację oprogramowania na pakiety o rozmiarze ≤ MTU, sekwencyjne wysyłanie przez Notify/Write, weryfikację sumy kontrolnej każdego pakietu i potwierdzenie odbioru. Jeśli któryś pakiet zostanie utracony, urządzenie żąda ponownego wysłania. Niezawodność OTA krytycznie zależy od prawidłowego wyboru MTU i connection interval.
Zalecenia dla OTA: negocjuj maksymalne MTU (247–512 bajtów), ustaw connection interval 7.5–15 ms (jeśli urządzenie obsługuje), używaj DLE (Data Length Extension) do zwiększenia fizycznego pakietu do 251 bajtów. Dla urządzeń z ograniczoną pamięcią bufora (np. moduły BLE oparte na nRF52) sprawdzaj maksymalne MTU w specyfikacji układu.
Często zadawane pytania
Połączenie będzie używać domyślnego MTU — 23 bajtów. Dla większości scenariuszy IoT (przesyłanie odczytów czujników) to wystarczy. Do przesyłania dużych ilości danych prędkość będzie 5–10 razy niższa niż z negocjowanym MTU 247 bajtów.
Nie, MTU jest negocjowane jeden raz po połączeniu i nie może być zmienione bez rozłączenia i ponownego połączenia. Dlatego zaleca się negocjować MTU zaraz po wykryciu usług, przed rozpoczęciem aktywnego przesyłania danych.
Są to historycznie ustalone empiryczne maksima dla każdego stosu. Rzeczywiste ATT MTU i tak jest ograniczone do 257 bajtów zgodnie ze specyfikacją. Stosy automatycznie fragmentują dane większe niż 251 bajtów na kilka pakietów, więc różnica między 512 a 517 jest nieistotna.
MTU — rozmiar żądania GATT na poziomie ATT. DLE — rozmiar fizycznego pakietu w warstwie Link Layer. Bez DLE każde żądanie GATT (do 247 bajtów) jest fragmentowane na pakiety po 27 bajtów. Z DLE — przesyłane jest w jednym pakiecie. Dla maksymalnej prędkości należy negocjować oba parametry.
Dla trackera fitness przesyłającego odczyty tętna i kroki standardowe MTU 23 bajtów wystarczy. Jeśli wymagane jest przesyłanie historii treningów (objętość 10–50 KB) — negocjuj MTU 247 bajtów, aby przyspieszyć synchronizację danych przy połączeniu ze smartfonem.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również