வலைப்பதிவுக்குத் திரும்பு
Transport19 min read

Wi-Fi Aware போக்குவரத்து வடிவமைப்பு — அயலக கண்டுபிடிப்பு & தரவு பாதைகள்

PlainApp எப்படி Wi-Fi Aware-ஐ (NAN — Neighbor Awareness Networking) அதன் பியர் போக்குவரத்து fallback சங்கிலியின் நடுத்தர அடுக்காக, LAN (அதே-சப்நெட் HTTPS) மற்றும் BLE (கடைசி-முயற்சி GATT RPC) இடையே பயன்படுத்துகிறது என்பதை இக்கட்டுரை விளக்குகிறது. இரண்டு PlainApp சாதனங்கள் வெவ்வேறு SSID-களில், guest vs IoT VLAN-களில், அல்லது Wi-Fi உள்கட்டமைப்பே இல்லாமல் இருக்கும்போது பேச உதவுவது Wi-Fi Aware — DHCP சேவையகத்திடமிருந்து IP முகவரி தேவையே இல்லாமல்.

இக்கட்டுரை Android-மட்டும் Aware அமர்வு வாழ்க்கைச்சுழற்சி, publish / subscribe கண்டுபிடிப்பு மாதிரி, ஃப்ரேம்வொர்க்கின் ~500 ms சாளரத்திற்குள் இரு தரப்பிலும் requestNetwork-ஐ ஒருங்கிணைக்கும் இரண்டு-கட்ட பங்கு-பிரிப்பு handshake, ஒருங்கிணைந்த sweeping-உடன் பியர்-வாரி இணைப்பு குளம், ஒற்றை OkHttp கிளையன்ட் LAN மற்றும் Aware இரண்டையும் பணியாற்ற அனுமதிக்கும் IPv6 + தனிப்பயன்-DNS தந்திரம், மற்றும் BLE வழியாக பியர் Aware தொடக்கத்தைத் தூண்டும் prewarmer ஆகியவற்றை உள்ளடக்கியது.

பரந்த fallback சங்கிலிக்கு, அரட்டைக் கட்டமைப்பு-ஐப் பார்க்கவும். Aware கிடைக்காதபோது ஏற்றுக்கொள்ளும் BLE போக்குவரத்திற்கு, BLE போக்குவரத்து-ஐப் பார்க்கவும். Aware PMK-ஆக மீண்டும் பயன்படுத்தப்படும் பகிரப்பட்ட ChaCha20 விசை எப்படி நிறுவப்படுகிறது என்பதற்கு பெயரிங் பாய்வு-ஐப் பார்க்கவும்.

பொருளடக்கம்

Wi-Fi Aware ஏன்? {#why-wi-fi-aware}

Wi-Fi Aware (IEEE 802.11bc, முன்பு NAN — Neighbor Awareness Networking) என்பது இரண்டு சாதனங்கள் எந்த Wi-Fi உள்கட்டமைப்பும் இல்லாமலேயே ஒன்றையொன்று கண்டுபிடித்து தரவைப் பரிமாற அனுமதிக்கும் ஒரு Wi-Fi Alliance சான்றிதழ் — AP இல்லை, ரவுட்டர் இல்லை, DHCP இல்லை. PlainApp அதை LAN மூட முடியாத இரண்டு சூழ்நிலைகளுக்குப் பயன்படுத்துகிறது:

  • வெவ்வேறு SSID-கள் / VLAN-கள். guest நெட்வொர்க்கில் ஒரு தொலைபேசி மற்றும் IoT VLAN-இல் ஒரு மடிக்கணினி இரண்டும் Wi-Fi வழியாக "ஆன்லைனில்" இருந்தாலும் ஒன்றையொன்றின் IP-ஐ அடைய முடியாது. Aware உள்கட்டமைப்பைத் தவிர்த்து ஒரு நேரடி சாதனத்திலிருந்து-சாதனம் தரவுப் பாதையை உருவாக்குகிறது.
  • உள்கட்டமைப்பே இல்லை. Wi-Fi ஆன் ஆக இருந்தாலும் AP இல்லாமல் காட்டில் இரண்டு சாதனங்கள் இன்னும் அரட்டையாடலாம். (BLE-உம் இதை மூடுகிறது, ஆனால் Aware மிக வேகமானது — விநாடிகளுக்கு பதிலாக ~10 ms ரவுண்ட் ட்ரிப்கள், மற்றும் பத்துகள் KB/s-க்கு பதிலாக MB/s.)

Diagram 1
1

தள கட்டுப்பாடுகள்

Wi-Fi Aware PlainApp-இல் Android-மட்டும்:

  • Android 13 (API 33) குறைந்தபட்சம் — PlainApp சார்ந்திருக்கும் setPort() மற்றும் setPmk() overloads உடன் WifiAwareNetworkSpecifier.Builder isTPlus()-ஐ வேண்டும்.
  • iOS மூன்றாம் தரப்பு செயலிகளுக்கு Wi-Fi Aware-ஐ வெளிப்படுத்துவதில்லை. iOS PlainApp LAN-இலிருந்து நேரடியாக BLE-க்கு விழுகிறது; WifiAwareTransport object iOS இலக்காக ஒருபோதும் தொகுக்கப்படுவதில்லை (@RequiresApi(Build.VERSION_CODES.S) + androidMain மூலத் தொகுப்பு).

இதுதான் PeerTransportRouter.buildList createWifiAwareTransport()-ஐ அழைப்பதற்கான காரணம் — iOS-இல் null-ஐத் திருப்பி அனுப்பும் ஒரு factory.

Fallback சங்கிலியில் Aware எங்கே அமர்ந்திருக்கிறது {#where-aware-sits-in-the-fallback-chain}

PlainApp-ன் PeerTransportRouter ஒரு வரிசையான பட்டியல். ஒவ்வொரு send அல்லது downloadFile அழைப்பிற்கும், அது பட்டியலை நடந்து ஒன்று வெற்றிபெறும் வரை ஒவ்வொரு போக்குவரத்தையும் முயற்சிக்கிறது; தோல்விகள் கீழே நீர்வீழ்ச்சி செய்கின்றன.

Diagram 2
2

Aware "நடுவில்" தான் ஏன், "முதலில்" அல்ல?

ஏனெனில் LAN கிடைக்கும்போது கிட்டத்தட்ட எப்போதும் வேகமானது. AP வழியாக ஒரு அதே-சப்நெட் Wi-Fi hop என்பது ஒரு ஒற்றை 802.11 சட்டக பரிமாற்றம்; ஒரு Aware தரவுப் பாதை ஒரு NDP அமைப்பு (முதல் பயன்பாட்டில் ~5 வி) மற்றும் சாதனத்திலிருந்து-சாதனம் இணைப்புக்கான இரண்டாவது Wi-Fi ரேடியோ context-ஐச் சேர்க்கிறது. இரண்டும் அடையக்கூடியவை என்றால், LAN தாமதம் மற்றும் செயல்திறனில் வெல்கிறது.

மாறாக, BLE எப்போதும் மெதுவானது — ஆனால் இரண்டு சாதனங்களும் பெயர் செய்யப்பட்டால் வேலை செய்கிறது. Aware நடுவில் உள்ளது: BLE-விட வேகமானது, LAN-விட மெதுவானது, மற்றும் Wi-Fi ஆன் உடன் Android 13+ சாதனங்களில் மட்டுமே கிடைக்கிறது.

அமர்வு வாழ்க்கைச்சுழற்சி: Attach → Publish + Subscribe {#session-lifecycle-attach--publish--subscribe}

ஒரு Wi-Fi Aware அமர்வு செயல்முறை-அளவு. ஒரு சாதனத்திற்கு சரியாக ஒரு WifiAwareSession; அதற்குள், PlainApp ஒரு publish அமர்வு (பியர்கள் எங்களைக் கண்டுபிடிக்க) மற்றும் ஒரு subscribe அமர்வு (நாங்கள் பியர்களைக் கண்டுபிடிக்க) இரண்டையும் இயக்குகிறது. AwareSession.start() attach கால்பேக்கை முடிக்கும் கணத்தில் இரண்டும் தொடங்கப்படுகின்றன.

Diagram 3
3

ஏன் ஒரே சாதனத்தில் publish மற்றும் subscribe?

Wi-Fi Aware கண்டுபிடிப்பு மாதிரி சமச்சீரற்றது: ஒரு publisher ஒரு சேவையை விளம்பரப்படுத்துகிறது, ஒரு subscriber அதைத் தேடுகிறது. கண்டுபிடிப்பை சமச்சீராக்க (இரு சாதனங்களும் ஒன்றையொன்று கண்டுபிடிக்க), PlainApp இரண்டையும் ஒரே நேரத்தில் செய்கிறது. இல்லாவிட்டால், A சாதனம் ஒரு குறிப்பிட்ட பியருக்கு அது publisher அல்லது subscriber என்பதை முன்கூட்டியே தெரிந்துகொள்ள வேண்டும் — ஆனால் பியர் பங்குகள் பின்னர் clientId ஒப்பீட்டால் தீர்மானிக்கப்படுகின்றன (கண்டுபிடிப்பு & பங்கு ஒதுக்கீடு-ஐப் பார்க்கவும்).

ஒரே நேரத்தில் publish மற்றும் subscribe செய்வது என்பது ஒவ்வொரு சாதனமும் மறுபக்கத்தின் onServiceDiscovered-ஐ (subscriber ஆக) AND மறுபக்கத்தின் hello செய்திகளைப் பெறுகிறது (publisher ஆக) — handshake-ன் இரு திசைகளும் எப்போதும் கிடைக்கின்றன.

முடிவடைப்பில் தானியங்கு-மறுதொடக்கம்

சில Android மாறுபாடுகள் (குறிப்பாக MIUI) பேட்டரியைச் சேமிக்க நீண்ட-கால Aware அமர்வுகளைக் கொல்கின்றன. PlainApp இதை onSessionTerminated கால்பேக்குகளில் கையாளுகிறது: அது முடிக்கப்பட்ட அமர்வை null செய்து, இன்னும்-இணைக்கப்பட்ட WifiAwareSession-இல் உடனடியாக publishOwnService / subscribeOwnService-ஐ மீண்டும் அழைக்கிறது. Attach அமர்வு இழக்கப்படவில்லை — publish/subscribe கண்டுபிடிப்பு அமர்வு மட்டுமே. முடிவடைப்பிற்கு முந்தைய பியர் handles பழையதாகின்றன, இதனால் awaitPeerHandle discoveredAt நேரமுத்திரையைச் சரிபார்த்து, 30 வி-க்கு பழைய handles-ஐ நீக்குகிறது.

கண்டுபிடிப்பு & பங்கு ஒதுக்கீடு {#discovery--role-assignment}

Wi-Fi Aware தரவு-பாதை நெறிமுறை ஒரு பக்கம் publisher (சேவையகம்) ஆகவும் மற்றொன்று subscriber (கிளையன்ட்) ஆகவும் செயல்பட வேண்டும். இரு தரப்பும் ஒரே நேரத்தில் initiator ஆக முடியாது — ஃப்ரேம்வொர்க் பொருந்தக்கூடிய counterpart இல்லாத கோரிக்கைகளை நிராகரிக்கிறது.

PlainApp clientIds-ன் எளிய lexicographic ஒப்பீட்டைப் பயன்படுத்தி பியர்-வாரியாக நிர்ணயமாக பங்குகளை ஒதுக்குகிறது:

Diagram 4
4

நிர்ணயமானது ஏன், பேச்சுவார்த்தை செய்யப்பட்டது அல்ல?

ஒரு பேச்சுவார்த்தை அணுகுமுறை (உ.ம். "குறைந்த MAC சேவையகம்") ஒரு கூடுதல் செய்திப் பரிமாற்றம் தேவைப்படும். Lexicographic ஒப்பீடு idempotent, சமச்சீர், மற்றும் stateless: இரு சாதனங்களும் எந்தத் தகவல்தொடர்பும் இல்லாமல் அதே ஜோடிக்கு அதே பங்கைக் கணக்கிடுகின்றன. clientId ஒரு 13-எழுத்து short UUID, எனவே ties (clientId == peer.id) ஒரு பியரை அதனுடனேயே ஒப்பிடும்போது மட்டுமே நிகழும் — இது ஒருபோதும் போக்குவரத்தை அடைவதில்லை.

பங்கு இரண்டு விஷயங்களை downstream தீர்மானிக்கிறது:

  1. யார் மறுமுயற்சி வளையத்தை இயக்குகிறார்கள். கிளையன்ட் மட்டுமே requestNetwork-ஐ மறுமுயற்சி செய்கிறது; சேவையகம் ஒவ்வொரு hello-க்கும் சரியாக ஒரு முயற்சி செய்கிறது. இது 500 ms சாளரத்திற்கு முக்கியம் (அடுத்த பிரிவு).
  2. யார் port-ஐ அமைக்கிறார்கள். Publisher தனது HTTPS சேவையக port-இல் உள்வரும் இணைப்புகளை ஏற்பதால் setPort(httpsPort)-ஐ அழைக்கிறது. Subscriber port-ஐ அமைக்காது — தரவுப் பாதை நிறுவப்பட்ட பிறகு WifiAwareNetworkInfo-இலிருந்து பியரின் port-ஐக் கற்றுக்கொள்கிறது.

இரண்டு-கட்ட handshake (hello + ready) {#the-two-phase-handshake-hello--ready}

Wi-Fi Aware தரவு-பாதை அமைப்பின் கடினமான பகுதி timing. ஃப்ரேம்வொர்க் இரு தரப்பையும் ஒன்றையொன்றிடமிருந்து தோராயமாக 500 ms-க்குள் connectivityManager.requestNetwork-ஐ அழைக்க வேண்டும் — ஒரு தரப்பு மறு தரப்பு அதன் பொருந்தக்கூடிய கோரிக்கையைப் பதிவுசெய்வதற்கு முன்பு அதை அழைத்தால், ஃப்ரேம்வொர்க் onUnavailable ("releaseRequestAsUnfulfillableByAnyFactory") உடன் உடனடியாக நிராகரிக்கிறது.

PlainApp இதை Aware L2 செய்திச் சேனலின் மேல் இயங்கும் (onServiceDiscovered-ஆல் பயன்படுத்தப்படும் அதே sendMessage API) ஒரு இரண்டு-செய்தி பயன்பாட்டு-அடுக்கு handshake-உடன் தீர்க்கிறது:

Diagram 5
5

ஏன் இரண்டு செய்திகள் (hello + ready), ஒன்று அல்ல?

hello மட்டும் போதாது, ஏனெனில் திசை சமச்சீரின்மை. Subscriber publisher-ஐக் கண்டுபிடிக்கும் கணத்தில் (onServiceDiscovered-இல்) hello-ஐ அனுப்ப முடியும், ஆனால் publisher subscriber-ன் PeerHandle-ஐப் பெறும் வரை requestNetwork-ஐத் தொடங்க முடியாது, அது hello-ஐப் பெறுவதன் மூலம் மட்டுமே கற்றுக்கொள்கிறது. எனவே hello இரண்டு நோக்கங்களைக் கொண்டுள்ளது:

  1. subscriber-ன் PeerHandle-ஐ publisher-க்கு வழங்குதல். Publisher-க்கு அது WifiAwareNetworkSpecifier-ஐ உருவாக்கத் தேவை.
  2. இணைக்க நோக்கத்தை சமிக்ஞை செய்தல். hello-ஐப் பெறுவது publisher-க்கு "subscriber requestNetwork செய்யப்போகிறார், எனவே நானும் செய்ய வேண்டும்" எனக் கூறுகிறது.

ready ரசீது எதிர் திசைக்கு இருக்கிறது — subscriber-க்கு "publisher அவரது requestNetwork-ஐப் பதிவுசெய்துவிட்டார்" எனக் கூற. இது இல்லாவிட்டால், subscriber-ன் requestNetwork publisher-ன் request-ஐ விட முன்னே ஓடி, ஃப்ரேம்வொர்க்கால் நிராகரிக்கப்படலாம். ready ரசீது ஒரு non-blocking சமிக்ஞை: subscriber requestNetwork-ஐ அழைப்பதற்கு முன்பு அதற்காக காத்திருப்பதில்லை (அது ஒரு ரவுண்ட் ட்ரிப்பைச் சேர்க்கும்), ஆனால் அது subscriber IDLE நிலையில் (மறுமுயற்சி முயற்சிகளுக்கு இடையில்) இருக்கும்போது வந்தால், subscriber RETRY_DELAY_MS இடைவெளிக்குக் காத்திருக்காமல் உடனடியாக மறுமுயற்சி செய்யலாம்.

மறுமுயற்சி-வளைய சமச்சீரின்மை

இது வடிவமைப்பின் மிகச் சூக்ஷ்மமான பகுதி. subscriber மட்டுமே மறுமுயற்சி செய்கிறது. Publisher ஒவ்வொரு hello-க்கும் சரியாக ஒரு requestNetwork முயற்சியை மேற்கொள்கிறது. இதற்குக் காரணம்:

  • இரு தரப்பும் சுயாதீனமாக மறுமுயற்சி செய்தால், அவற்றின் மறுமுயற்சி சுழற்சிகள் கட்டத்திற்கு வெளியே நகரும் (வெவ்வேறு delay() காலஅளவுகள், வெவ்வேறு GC இடைநிறுத்தங்கள்), மற்றும் இரண்டு requestNetwork அழைப்புகளும் 500 ms சாளரத்திற்குள் அரிதாகவே ஒன்றாக இருக்கும்.
  • subscriber-ன் மறுமுயற்சி வளையம் ஒவ்வொரு முயற்சியிலும் ஒரு புதிய hello-ஐ அனுப்புகிறது, இது publishHelloListeners வழியாக publisher-ன் buildLink-ஐ மறு-தூண்டுகிறது. இது publisher-ன் requestNetwork எப்போதும் hello-ஐத் தொடர்ந்து ~50 ms-க்குப் பிறகு வருவதை உத்தரவாதம் செய்கிறது, 500 ms சாளரத்திற்குள் நன்றாக.

இது AwarePeerLink.build-இல் விரிவாக ஆவணப்படுத்தப்பட்டுள்ளது.

NDP requestNetwork — 500 ms சாளரம் {#ndp-requestnetwork--the-500-ms-window}

requestNetwork அழைப்பு Aware போக்குவரத்தில் மிக டைமிங்-உணர்திறன் கொண்ட செயல்பாடு. ஒவ்வொரு பக்கத்திலும் என்ன நிகழ்கிறது:

Diagram 6
6

onUnavailable கால்பேக்கின் பொருள்

onUnavailable ஃப்ரேம்வொர்க் பொருந்தக்கூடிய பியர் request-ஐக் கண்டுபிடிப்பதற்கு முன்பு requestNetwork-ஐ நிராகரிக்கும்போது இயங்குகிறது. PeerHandle இன்னும் செல்லுபடியாகும் — NDP (Neighbor Discovery Protocol) pairing மட்டுமே தோல்வியடைந்தது, ஏனெனில் மறு தரப்பு இன்னும் பதிவுசெய்யவில்லை. PlainApp இந்த வழக்கில் session.invalidatePeerHandle-ஐ வேண்டுமென்றே அழைப்பதில்லை, ஏனெனில் handle-ஐ invalidate செய்வது onServiceDiscovered ஒருபோதும் அழைக்கப்பட்டதற்கான ஒரே சமிக்ஞையை (ஒவ்வொரு subscribe அமர்வு வாழ்நாளிலும் ஒரு பியருக்கு ஒருமுறை இயங்குகிறது) நீக்கிவிடும். Handle பாதுகாக்கப்பட்டால், மறுமுயற்சி ஒரு புதிய கண்டுபிடிப்புக்குக் காத்திருக்காமல் அதை மீண்டும் பயன்படுத்தலாம்.

அதே onMessageReceived-இலிருந்து publisher-பக்க handle-க்கும் பொருந்தும் — publisher தோல்வியடைந்த முயற்சிகளிலும் publishPeerHandles[fromCid] உள்ளீட்டை வைத்திருக்கிறது, எனவே subscriber-ன் அடுத்த hello கேஷ் செய்யப்பட்ட handle-ஐ மீண்டும் பயன்படுத்துகிறது, கைவிடப்படுவதற்கு பதிலாக.

ஒவ்வொரு பெயர் செய்த பியருக்கும் அதன் சொந்த AwarePeerLink object உள்ளது, செயல்முறை-அளவு AwareLinkPool-ஆல் வைத்திருக்கப்படுகிறது. குளம் கண்டுபிடிப்பு நிகழ்வுகள், இணைப்பு மறுபயன்பாடு, மற்றும் ஒருங்கிணைந்த eviction ஆகியவற்றைக் கையாளுகிறது.

Diagram 7
7

கண்டுபிடிப்பில் ஏன் auto-build இல்லை?

குளம் வெளிப்படையாக onServiceDiscovered இயங்கும்போது ஒரு இணைப்பை உருவாக்குவதில்லை. இது ஒரு முக்கிய முடிவு: ஒரு பிஸியான காபி கடையில் 100 PlainApp சாதனங்கள் அனைத்தும் "plain-peer" சேவையை வெளியிடும். ஒவ்வொரு கண்டுபிடிப்பும் ஒரு requestNetwork-ஐத் தூண்டினால், ஃப்ரேம்வொர்க் NDP அமைப்பு முயற்சிகளால் நிரம்பி, Wi-Fi ரேடியோ saturated ஆகிவிடும்.

அதற்குப் பதிலாக, குளம் PeerHandle-ஐ மட்டுமே பதிவு செய்து, பின்வருபவற்றில் ஒன்றிற்காக காத்திருக்கிறது:

  1. உள்ளக பயனர் ஒரு செய்தியை அனுப்புகிறார்WifiAwareTransport.sendpool.buildLink(peer) (அனுப்புநர்-பக்க தூண்டல்).
  2. தொலைநிலை பியர் ஒரு hello-ஐ அனுப்புகிறதுonPublishHelloReceivedbuildLink(peer) (பெறுநர்-பக்க தூண்டல்).
  3. தொலைநிலை பியர் ஒரு ready-ஐ அனுப்புகிறதுonSubscribeReadyReceivedbuildLink(peer) (பெறுநர்-பக்க தூண்டல்).

இவ்வாறு, இணைப்புகள் பயனர் உண்மையில் செய்திகளைப் பரிமாறும் பியர்களுக்கு மட்டுமே உருவாக்கப்படுகின்றன — ரேடியோ வரம்பில் உள்ள ஒவ்வொரு PlainApp சாதனத்திற்கும் அல்ல.

ஒருங்கிணைந்த sweep

ஒவ்வொரு 10 விநாடிகளுக்கும், குளம் எல்லா இணைப்புகளையும் நடந்து, lastActiveAt 60 விநாடிகளுக்கு பழையதாக இருக்கும் எதையும் மூடுகிறது. ஒவ்வொரு send மற்றும் downloadFile-உம் நேரமுத்திரையைப் புதுப்பிக்க link.touch()-ஐ அழைக்கிறது. இது பயனர் அரட்டையடித்து நிறுத்திய பியர்களுக்கான Wi-Fi ரேடியோ context மற்றும் OkHttp இணைப்பு குளத்தை மீட்டெடுக்கிறது — முக்கியம், ஏனெனில் Android ஒரே நேர Aware தரவுப் பாதைகளின் எண்ணிக்கையை தோராயமாக 4–10-ஆக கட்டுப்படுத்துகிறது (சாதனத்தைப் பொறுத்து).

IPv6 முகவரியிடல் & plain-aware-peer DNS தந்திரம் {#ipv6-addressing--the-plain-aware-peer-dns-trick}

Wi-Fi Aware தரவுப் பாதைகள் link-local IPv6 மட்டும் பயன்படுத்துகின்றன. IPv4 இல்லை, DNS சேவையகம் இல்லை, DHCP இல்லை. பியரின் IPv6 முகவரி onCapabilitiesChanged-இல் WifiAwareNetworkInfo.peerIpv6Addr புலம் வழியாக வழங்கப்படுகிறது — ஒரு fe80::... முகவரி, அது Aware நெட்வொர்க் இடைமுகத்தில் மட்டுமே அர்த்தமுள்ளது.

PlainApp-க்கு இந்த முகவரிக்கு HTTPS கோரிக்கைகளை அனுப்ப வேண்டும், ஆனால் OkHttp-ன் https:// URL parsing ஒரு hostname-இல் raw IPv6 literal-ஐ நிராகரிக்கிறது (https://[fe80::abcd]:8443/ வேலை செய்யும், ஆனால் அதை தனிப்பயன் Dns resolver வழியாக ரூட் செய்வது தூய்மையானது). தந்திரம்:

Diagram 8
8

ஏன் ஒரு sentinel hostname?

மாற்று — IPv6 literal-ஐ URL-இல் நேரடியாக அனுப்புவது — ஒவ்வொரு call site-உம் link-local முகவரியைத் தெரிந்துகொள்ள வேண்டும். ஒரு sentinel hostname-ஐப் பயன்படுத்துவதன் மூலம், URL கட்டமைப்பு LAN மற்றும் Aware இரண்டிற்கும் ஒரே மாதிரி: இரண்டும் OkHttp parse செய்யக்கூடிய செல்லுபடியாகும் https://<host>:<port>/peer_graphql URL-ஐ உருவாக்குகின்றன. ஒரே வித்தியாசம் கிளையன்டுடன் பிணைக்கப்பட்ட Dns செயலாக்கம் — LAN சிஸ்டம் DNS-ஐப் பயன்படுத்துகிறது, Aware sentinel hostname-க்கு கேஷ் செய்யப்பட்ட link-local முகவரியைத் திருப்பி அனுப்பும் மற்றும் வேறெதற்கும் Dns.SYSTEM-க்கு விழும் awareDns(peerIpv6)-ஐப் பயன்படுத்துகிறது.

ஏன் network.socketFactory?

Android-ன் Network object ஒரு குறிப்பிட்ட நெட்வொர்க் இடைமுகத்தை (இந்த வழக்கில், Aware தரவுப் பாதை) குறிக்கிறது. network.socketFactory-ஐ அழைத்து அதை OkHttp-ன் socketFactory config-க்கு அனுப்புவதன் மூலம், எல்லா TCP sockets-உம் Aware இடைமுகத்தில் உருவாக்கப்பட கட்டாயப்படுத்துகிறோம் — இயல்புநிலை Wi-Fi அல்லது cellular இடைமுகம் அல்ல. இது இல்லாவிட்டால், OS கோரிக்கையை இயல்புநிலை நெட்வொர்க் வழியாக ரூட் செய்யும், அங்கு link-local IPv6 அடைய முடியாதது, மேலும் கோரிக்கை ENETUNREACH உடன் தோல்வியடையும்.

மறையாக்கவியல்: PMK வழிப்பாடு & ChaCha20 மறுபயன்பாடு {#cryptography-pmk-derivation--chacha20-reuse}

Wi-Fi Aware தரவுப் பாதைக்கு ஒரு optional PMK (Pairwise Master Key)-ஐ ஆதரிக்கிறது. அமைக்கப்பட்டால், L2 link அந்த PMK-உடன் மறைகுறியாக்கப்படுகிறது — Wi-Fi ரேடியோ மறைகுறியாக்கத்தைக் கையாளுகிறது, பயன்பாட்டு-அடுக்கு மறைகுறியாக்கம் தேவையில்லை.

PlainApp PMK-ஐ LanTransport மற்றும் BleTransport பயன்பாட்டு-அடுக்கு மறைகுறியாக்கத்திற்கு பயன்படுத்தும் அதே ChaCha20 பகிரப்பட்ட விசையிலிருந்து பெறுகிறது:

Diagram 9
9

ஏன் 32 பைட்டுகளுக்கு துண்டிக்கப்படுகிறது?

Wi-Fi Aware PMK சரியாக 32 பைட்டுகள் (256 பிட்) ஆக இருக்க வேண்டும். பெயரிங்கிலிருந்து ChaCha20 பகிரப்பட்ட விசை இயல்பான வழக்கில் 32 பைட்டுகள், எனவே raw.size == 32 கிளை பொதுவான பாதை. துண்டிப்பு/திணிப்பு fallback விசை குறைவாக சேமிக்கப்பட்ட (கோட்பாட்டு) வழக்கைக் கையாளுகிறது — 32 பைட்டுகளுக்கு பூஜ்யங்களுடன் திணிப்பது ஒரு தற்காப்பு நடவடிக்கை, சரியாகப் பெயர் செய்த பியர்களுடன் நடைமுறையில் நிகழ்வதில்லை.

கையொப்பமிடப்பட்ட உறை LAN-உடன் ஒரே மாதிரி

createCryptoHttpClient LanTransport-ஆல் பயன்படுத்தப்படும் அதே factory என்பதால், Aware-இல் L7 மறைகுறியாக்கம் LAN-உடன் byte-for-byte ஒரே மாதிரி. சேவையக-பக்க PeerGraphQLService எந்தப் போக்குவரத்து கோரிக்கையை வழங்கியது என்பதை அறியாது (அல்லது கவலைப்படாது) — அது வெறுமனே ஒரு கையொப்பமிடப்பட்ட, மறைகுறியாக்கப்பட்ட GraphQL சுமையைப் பார்த்து, பியரின் பகிரப்பட்ட விசையுடன் மறைநீக்குகிறது. இதுதான் அரட்டைக் கட்டமைப்பு-இல் ஆவணப்படுத்தப்பட்ட "ஒரு குறியீட்டுத்தளம், பல போக்குவரத்துகள்" கொள்கை.

செய்தி அனுப்பல் பாதை (முழுமையான) {#message-send-path-end-to-end}

எல்லாவற்றையும் ஒன்றிணைத்தால் — ஒரு அரட்டைச் செய்தி Wi-Fi Aware வழியாக அனுப்பப்படும்போது என்ன நிகழ்கிறது:

Diagram 10
10

குறிப்பிடத்தக்க வடிவமைப்புத் தேர்வுகள்

  • இணைப்பு மறுபயன்பாடு. BleTransport-போல அல்லாமல், அது ஒவ்வொரு கோரிக்கைக்கும் பிறகும் GATT இணைப்பை இடிக்கிறது, WifiAwareTransport 60 வி ஒருங்கிணைந்த சாளரத்திற்குள் பயனர் செய்யும் பல கோரிக்கைகளுக்கும் Aware தரவுப் பாதையை மறுபயன்பாடு செய்கிறது. முதல் கோரிக்கை ~400 ms handshake-ஐச் செலுத்துகிறது; அடுத்தடுத்த கோரிக்கைகள் ~10 ms ரவுண்ட் ட்ரிப்கள்.
  • LAN-ன் அதே மறைகுறியாக்கம். ChaCha20 இடைமறிப்பான் மற்றும் கையொப்பமிடப்பட்ட உறை LAN-உடன் byte-ஒரே மாதிரி. பியரின் PeerGraphQLService எந்தப் போக்குவரத்து கோரிக்கையை வழங்கியது என்பதை அறியாது.
  • இணைப்பு தோல்வியில் preemption இல்லை. buildLink தோல்வியடைந்தால், போக்குவரத்து TransportUnavailable-ஐ வீசி ரூட்டர் BLE-க்கு விழுகிறது. send-இல் மறுமுயற்சி இல்லை — AwarePeerLink.build ஏற்கனவே அதன் சொந்த உள் மறுமுயற்சி வளையத்தைச் செய்கிறது (கிளையன்ட்டில் MAX_BUILD_ATTEMPTS = 1, prewarmer இரு தரப்பையும் primed செய்திருந்தால் அதிகம்).

கோப்பு பதிவிறக்கப் பாதை (முழுமையான) {#file-download-path-end-to-end}

Aware வழியாக கோப்பு பதிவிறக்கங்கள் அரட்டைச் செய்திகளைப் போல அதே தரவுப் பாதையை மறுபயன்பாடு செய்கின்றன, ஆனால் பெரிய கோப்புகளை ஸ்ட்ரீம் செய்வதற்கு உள்ளமைக்கப்பட்ட தனி OkHttp கிளையன்ட்-ஐப் பயன்படுத்துகின்றன:

Diagram 11
11

பதிவிறக்கங்களுக்கு ஏன் தனி கிளையன்ட்?

அரட்டை கிளையன்ட் (AwareHttpClientFactory.build) 30 வி requestTimeoutMillis-ஐக் கொண்டுள்ளது — GraphQL mutations-க்கு பொருத்தமானது ஆனால் 100 MB கோப்பு பதிவிறக்கத்திற்கு பேரழிவு. பதிவிறக்க கிளையன்ட் (buildFileDownload) பின்வருவனவற்றை அமைக்கிறது:

  • connectTimeoutMillis = 10_000 (அரட்டையின் 5 வி-விட அதிகம், புதிய தரவுப் பாதையில் மெதுவான முதல்-பாக்கெட்டை அதிக சகிப்புத்தன்மை கொண்டது)
  • ஒரு வாசிப்புக்கு readTimeout = 120 வி (10 வி இயல்புநிலைக்கு பதிலாக)
  • requestTimeoutMillis = 120_000 (2 நிமிடங்கள் — பெரும்பாலான கோப்புகளுக்குப் போதுமானது)
  • retryOnConnectionFailure(true) — கைவிடப்பட்ட நடு-பதிவிறக்க வாசிப்பு மறுமுயற்சி செய்யப்படுகிறது, முழு பரிமாற்றத்தையும் தோல்வியடையச் செய்வதற்கு பதிலாக

இது மேலும் ChaCha20 இடைமறிப்பானைத் தவிர்க்கிறது. /fs endpoint raw கோப்பு பைட்டுகளை வழங்குகிறது (கையொப்பமிடப்பட்ட GraphQL உறை அல்ல), மற்றும் L2 PMK (இருக்கும்போது) ஏற்கனவே ரேடியோ இணைப்பை மறைகுறியாக்குகிறது. ஒரு 50 MB வீடியோவை ChaCha20-உடன் மென்பொருளில் இரட்டை-மறைகுறியாக்கம் செய்வது CPU-ஐ வீணாக்கி பரிமாற்றத்தை மெதுவாக்கும்.

ஸ்ட்ரீமிங், buffering அல்ல

BLE பாதையைப் போல, Aware பதிவிறக்கங்கள் கோப்பை ஒரு ByteReadChannel வழியாக ஸ்ட்ரீம் செய்கின்றன — கோப்பு பைட்டுகள் வரும்போது தற்காலிகக் கோப்பில் எழுதப்படுகிறது, நினைவகத்தில் buffer செய்யப்படவில்லை. PeerFileDownloader 8 KB துண்டுகளைப் படித்து ஒவ்வொரு விநாடியும் முன்னேற்ற நிகழ்வுகளை வெளியிடுகிறது. அதே DownloadedResponse / PeerFileDownloader / DownloadQueue பைப்லைன் எல்லா போக்குவரத்துகளிலும் மறுபயன்பாடு செய்யப்படுகிறது — போக்குவரத்து-குறிப்பிட்டது channel மூலம் மட்டுமே.

Prewarming: BLE-தூண்டப்பட்ட Aware தொடக்கம் {#prewarming-ble-triggered-aware-startup}

Aware பாதையில் மிகப் பெரிய பயனர்-காணக்கூடிய தாமதம் முதல் handshake — இரு தரப்பும் இன்னும் Aware-ஐத் தொடங்காவிட்டால், பயனரின் முதல் செய்தி பின்வருவனவற்றிற்காக காத்திருக்க வேண்டும்:

  1. உள்ளக Aware அமர்வு attach (~1 வி)
  2. உள்ளக publish + subscribe தொடக்கம் (~1 வி)
  3. தொலைநிலை பியரின் Aware தொடக்கம் (~2 வி BLE வழியாக)
  4. பரஸ்பர கண்டுபிடிப்பு (~1 வி)
  5. NDP handshake (~400 ms)

இது முதல் பைட் அனுப்பப்படுவதற்கு முன்பு ~5 விநாடிகள். இந்தத் தாமதத்தை மறைக்க, PeerTransportPrewarmer ChatPage நுழைவில் இயங்கி, தொலைநிலை பியரின் Aware தொடக்கத்தை BLE வழியாகத் தூண்டுகிறது:

Diagram 12
12

BLE-ன் இரட்டை பங்கு

BLE இங்கே இரண்டு நோக்கங்களை சேவையாற்றுகிறது:

  1. பியரின் தற்போதைய Aware நிலையைப் படி (மலிவானது, GATT connect இல்லை — ஸ்கேன் பதிலின் serviceData byte0 Aware கொடிகளைக் கொண்டு செல்கிறது).
  2. பியர் Aware-ஐத் தொடங்கத் தூண்டு அது ஆதரித்தாலும் தற்போது அதை இயக்கவில்லை என்றால். இது வழக்கமான BleTransport.send பாதையைப் பயன்படுத்துகிறது — ஒரு startAware GraphQL mutation பகிரப்பட்ட ChaCha20 விசையுடன் மறைகுறியாக்கப்பட்டு, GATT RPC வழியாகப் பியரின் /peer_graphql endpoint-க்கு வழங்கப்படுகிறது.

இது போக்குவரத்துகள் வெறுமனே fallback செய்வதற்குப் பதிலாக ஒத்துழைக்கும் சில இடங்களில் ஒன்று: BLE பயனர் கவனிக்கும் முன்பே அமர்வை வேகமான Aware போக்குவரத்திற்கு pre-emptively upgrade செய்யப் பயன்படுகிறது.

ஏன் நம்பிக்கையுடன் setAwareRunning(true)?

startAware mutation தொலைநிலை பியரின் resolver WifiAwareTransport.start()-ஐ அழைக்கும் வேளை வெற்றியைத் திருப்பி அனுப்புகிறது — ஆனால் Aware அமர்வு உண்மையில் attach செய்யப்படவில்லை (onAttached asynchronous ஆக இயங்குகிறது). PlainApp பியரை நம்பிக்கையுடன் awareRunning = true எனக் குறிக்கிறது, ஏனெனில்:

  • அது உண்மையில் தொடங்கினால், அடுத்த send Aware-ஐப் பயன்படுத்தும் (விரைவானது).
  • அது இல்லையென்றால் (உ.ம். பியரின் Wi-Fi ஆஃப்), அடுத்த send-ன் buildLinkTransportUnavailable உடன் தோல்வியடைந்து இயற்கையாக BLE-க்கு fallback செய்யும்.
  • ஒரு false positive-ன் செலவு ஒரு ~5 வி நேரமுடிவு, நிரந்தர block அல்ல — PeerCircuitBreaker தோல்வியைப் பதிவு செய்கிறது ஆனால் BLE காலைத் திறப்பதில்லை (BLE அதன் சொந்த தோல்விகளில் மட்டுமே திறக்கிறது).

ஏன் 30 வி-க்கு throttle?

PeerTransportPrewarmer.prewarm(peerId) ஒரு பியருக்கு ஒரு நேரமுத்திரையைப் பதிவு செய்து 30 வி-க்குள் மறு-இயக்கம் செய்ய மறுக்கிறது. இது ஏனெனில் பயனர் அரட்டை பட்டியல் மற்றும் அரட்டைப் பக்கத்திற்கு இடையில் அடிக்கடி வந்து செல்கிறார் — throttle இல்லாமல், ஒவ்வொரு navigation-உம் ஒரு BLE ஸ்கேன் + startAware mutation-ஐத் தூண்டும், பேட்டரியை வடிகட்டி BLE ரேடியோவை spam செய்யும். 30 வி சாளரம் வெறுமனே ஆன்லைனில் வந்த ஒரு பியரைப் பிடிக்கப் போதுமான அளவு குறுகியது (உ.ம். பயனர் தொலைநிலை சாதனத்தில் செயலியைத் திறந்தார்) ஆனால் போலி மறு-இயக்கங்களைத் தவிர்க்கப் போதுமான அளவு நீண்டது.

தோல்வி முறைகள் & விரைவு-தவிர் கொடி {#failure-modes--the-fast-skip-flag}

Aware மற்ற எந்தப் போக்குவரத்தை விடவும் அதிக தோல்வி முறைகளைக் கொண்டுள்ளது. isAwareRunning விரைவு-தவிர் கொடி முழு தொகுதியிலும் மிக முக்கியமான optimization — இது இல்லாவிட்டால், ஒவ்வொரு send-உம் BLE-க்கு fallback செய்வதற்கு முன்பு buildLink நேரமுடிவில் 10 வி-ஐ வீணாக்கும்.

Diagram 13
13

isAwareRunning கொடி linchpin

இந்த ஒற்றை boolean இல்லாமல், ஒவ்வொரு Aware send-உம்:

  • எப்போதும் buildLink-ஐ முயற்சிக்கும் → Aware இயங்காத ஒரு பியருக்கு ஒவ்வொரு send-இலும் 10 வி நேரமுடிவு.
  • எப்போதும் Aware-ஐத் தவிர்க்கும் → இரு தரப்பும் அதை இயக்கும்போதும் ஒருபோதும் பயன்படுத்தாது.

கொடி இரண்டு மூலங்களிலிருந்து, அதிகாரத்தின் வரிசையில் புதுப்பிக்கப்படுகிறது:

  1. BLE ஸ்கேன் பதில் (மலிவானது, GATT connect இல்லை) — PeerTransportPrewarmer.refreshAwareFlagFromScan-ஆல் அமைக்கப்படுகிறது. பியர் அதன் Aware நிலையை 9-பைட் serviceData சுமையில் (byte0 bitfield) விளம்பரப்படுத்துகிறது.
  2. GATT DISCOVER பதில் (அதிகாரப்பூர்வமானது) — முழு கண்டுபிடிப்பு நிகழும்போது PairingTransport.scanAndDiscover-ஆல் அமைக்கப்படுகிறது. இது ஸ்கேன் குறிப்பை மேலெழுதுகிறது.

False ஆக இருக்கும்போது, WifiAwareTransport.send மற்றும் downloadFile உடனடியாக TransportUnavailable-ஐ வீசுகின்றன — ஸ்கேன் இல்லை, handshake இல்லை, நேரமுடிவு இல்லை. ரூட்டர் microseconds-இல் BLE-க்கு விழுகிறது.

முக்கிய மாறிலிகள் குறிப்பு {#key-constants-reference}

மாறிலிமதிப்புஎங்கேநோக்கம்
AwareSession.SERVICE_NAME"plain-peer"கண்டுபிடிப்புஒவ்வொரு PlainApp சாதனத்தாலும் வெளியிடப்பட்டு subscribe செய்யப்பட்ட சேவைப் பெயர்
AwareSession.PEER_HANDLE_MAX_AGE_MS30 000PeerHandle cacheபழைய handles-ஐ நீக்கு (பியரின் publish அமர்வு மறுதொடக்கம் செய்யப்பட்டிருக்கலாம்)
AwareSession.READY_TIMEOUT_MS15 000Handshakepublisher-ன் ready ரசீதுக்காக subscriber காத்திருப்பு
AwareSession.MSG_HELLO0HandshakeSubscriber → Publisher செய்தி ID
AwareSession.MSG_READY1HandshakePublisher → Subscriber செய்தி ID
AwarePeerLink.MAX_BUILD_ATTEMPTS1Handshake (கிளையன்ட் மட்டும்)ஒற்றை முயற்சி — 3 ஆக இருந்தது, இப்போது 1 ஏனெனில் prewarmer இரு தரப்பையும் primes
AwarePeerLink.ATTEMPT_TIMEOUT_MS5 000Handshakeஒரு-முயற்சி நேரமுடிவு — 10 வி ஆக இருந்தது, fallback-ஐ வேகப்படுத்த பாதி செய்யப்பட்டது
AwarePeerLink.RETRY_DELAY_MS500Handshakeமறுமுயற்சி முயற்சிகளுக்கு இடையிலான தாமதம் (கிளையன்ட் மட்டும்)
AwarePeerLink.REQUEST_TIMEOUT_MS30 000NDPconnectivityManager.requestNetwork நேரமுடிவு
AwareLinkPool.IDLE_TIMEOUT_MS60 000Pool sweep60 வி செயல்பாடின்மைக்குப் பிறகு ஒருங்கிணைந்த இணைப்புகளை மூடு
AwareLinkPool.IDLE_SWEEP_INTERVAL_MS10 000Pool sweepSweep இடைவெளி
AwareHttpClientFactory.AWARE_HOST"plain-aware-peer"DNSதனிப்பயன் Dns-ஆல் peer IPv6-க்கு தீர்மானிக்கப்பட்ட Sentinel hostname
build அரட்டை கிளையன்ட்connectTimeout 5 வி, requestTimeout 30 வி, ChaCha20 இடைமறிப்பான்
buildFileDownloadconnectTimeout 10 வி, readTimeout 120 வி, requestTimeout 120 வி, மறைகுறியாக்கம் இல்லை
PeerTransportPrewarmer.PREWARM_TTL_MS30 000Prewarmஒரு பியருக்கு throttle
PeerTransportPrewarmer.BLE_SCAN_TIMEOUT_MS15 000PrewarmrefreshAwareFlagFromScan-க்கான BLE ஸ்கேன் நேரமுடிவு
PeerCircuitBreaker.WINDOW_MS30 000Circuit breakerவாசலுக்குப் பிறகு திறக்கும் காலம்
PeerCircuitBreaker.MAX_FAILURES2Circuit breakerதிறக்க வாசலுக்குள் தோல்விகள்
TempData.httpsPort8443 (இயல்புநிலை)ServerWifiAwareNetworkSpecifier.setPort வழியாக விளம்பரப்படுத்தப்பட்ட Publisher-ன் port
BleServiceData.AWARE_SUPPORTED0x01BLE ஸ்கேன் பதில்பியர் Wi-Fi Aware-ஐ ஆதரிக்கிறார் என்பதைக் குறிக்கும் bit
BleServiceData.AWARE_RUNNING0x02BLE ஸ்கேன் பதில்பியரின் Aware சேவை தற்போது இயங்குகிறது என்பதைக் குறிக்கும் bit

வடிவமைப்பு பரிமாற்றங்கள் சுருக்கம் {#design-trade-offs-recap}

Diagram 14
14

மேலும் படிப்பதற்கு

  • அரட்டைக் கட்டமைப்புWifiAwareTransport எப்படி LAN → Aware → BLE fallback சங்கிலி மற்றும் பரந்த அரட்டை அனுப்பு/பெறு பைப்லைனுக்குள் பொருந்துகிறது.
  • BLE போக்குவரத்து — Aware கிடைக்காதபோது ஏற்றுக்கொள்ளும் கடைசி-முயற்சி போக்குவரத்து; மேலும் prewarmer தொலைநிலை பியரில் Aware தொடக்கத்தைத் தூண்டப் பயன்படுத்தும் சேனல்.
  • பெயரிங் பாய்வு — Aware PMK-ஆக மீண்டும் பயன்படுத்தப்படும் பகிரப்பட்ட ChaCha20 விசை எப்படி நிறுவப்படுகிறது, மற்றும் BLE ஸ்கேன் பதில் கொடிகள் (AWARE_SUPPORTED / AWARE_RUNNING) எப்படி populate செய்யப்படுகின்றன.