基于Android完整UDP通信模塊的實現
TCP與UDP有什么差異?Android 設備上,一個手機通過熱點連接另一個手機。這種場景下,完整的 UDP 通信模塊應該考慮哪些方面,又應該如何優化。本文將圍繞這些問題展開描述。
TCP與UDP差異對比分析,UDP 在 Java 中的使用
v
我們都知道,開發一個 Android 應用程序,目前大多數還是使用的是 Java 語言。在 Java 語言中怎么去使用 UDP 協議呢?
其實 Socket 可以理解為對 TCP、UDP 協議在程序使用層面的封裝,提供出一些 api 來供程序員調用開發,這就是 Socket 最表層的含義。
在 Java 中,與 UDP 相關的類有 DatagramSocket、DatagramPacket 等,關于他們的使用,這里不著重介紹。
好了,假設大家對他們的使用都已大概了解,可以正式開始本文的內容了。
初始化一個 UDPSocket
首先創建一個叫 UDPSocket 的類。
在構造方法里,我們進行下一些初始化操作,簡單來說就是創建一個線程池,記錄一下當前時間毫秒值,至于他們有什么用,再往下看:
這里我們首先創建了一個 DatagramSocket 作為“客戶端”,其實 UDP 本身沒有客戶端和服務端的概念,只有發送方和接收方的概念,我們把發送方暫時當成是一個客戶端吧。
創建 DatagramSocket 對象時,傳入了一個端口號,這個端口號可以在一個范圍內自己定義,表示這個 DatagramSocket 在此端口上監聽數據。
然后又創建了一個 DatagramPacket 對象,作為數據的接收包。
最后調用 startSocketThread 啟動發送和接收數據的線程。
首先 clientThread 線程的目的是調用 DatagramSocket receive 方法,因為 receive 方法是阻塞的,不能放在主線程,所以自然開啟一個子線程了。receiveMessage 就是處理接受到的 UDP 數據報,我們先不看接受數據的這個方法,畢竟還沒人發消息呢,自然就談不上收了。
心跳包保持“長連接”
來到本文的第一個重點,我們都知道 UDP 本身沒有連接的概念。在 Android 端應用 UDP 和 TCP 的場景是一個手機連接另一個手機的熱點,二者處在同一局域網中。在二者并不知道對方的存在時,怎么才能發現彼此呢?
通過心跳包的方式,雙方都每隔一段時間發一個 UDP 包,如果對方接收到了,那就能知道對方的 ip,建立起通信了。
這段心跳的目的就是每隔十秒通過 sendMessage 發送一個消息,看看對方能不能收到。若對方收到消息,則刷新下 lastReceiveTime 的時間。
這里我每隔十秒向對方發送了一個字符串。
這里就是發送一個消息的代碼。最初在填寫 DatagramPacket 的參數之時,我有一個疑問,那個 targetAddress 其實是自己的 ip 地址。問題來了,我填寫了自己的 ip 地址和對方的端口,怎么可能找得到對方呢?你可能有一個疑惑 “192.168.43.255” 這個自己的 ip 地址是怎么來的,為什么要這么定義?
首先 android 手機開啟熱點,可以理解成一個網關,有一個默認的 ip 地址:“192.168.43.1”
這個 ip 地址不是我瞎編的一個,在 Android 源碼之中,就是這么定義的:
WifiStateMachine
所以我是知道所謂打開熱點一方的 ip 地址,而 UDP 發送消息時還有一個特性,就是發出去的消息,處在整個網關的設備是都可以接收到的,所以我自己的 ip 地址就定為了 “192.168.43.255”,所以這個 ip 地址和 “192.168.43.1” 在同一網關中,你發送的消息,它是可以收到的。
至于怎么判斷兩個 ip 地址是否處在同一網段中:
判斷兩個IP大小及是否在同一個網段中
來做一個階段總結:
首先我們創建了一個發送端 DatagramSocket,啟動了一個心跳程序,每間隔一段時間發送一個心跳包。
因為我知道熱點方的 ip 地址是默認的 “192.168.43.1”,并且 UDP 的特性就是發送的消息同一網段的設備都可以收到。所以發送方的 ip 地址定為了與熱點一方處在同一網段的 “192.168.43.255”。
事件與數據
事件與數據這兩個模塊與業務就緊密相關了。
先來說數據,雙方發送的數據格式你們可以隨意定義,當然我覺得還是定義成常規的 Json 格式就好。其中可以包含一些關鍵的事件字段:比如廣播心跳包、收到心跳包給對方上線的應答包、超時的下線包、以及各種業務相關的數據等等。
當然發送數據時是轉換成二進制數組發送的。發送中文字符、圖片等都沒有問題,但是可能有一些細節需要注意,隨時 google 一下就好了。
再來說下事件:
與業務無關的事件有哪些?
比如:
DatagramSocket.send 方法之后就是發送數據成功的事件;
DatagramSocket.receive 方法之后是數據接收成功的事件;
在心跳包發送一段時間,仍沒有接到回信時,是連接超時的事件;
與業務相關的事件就和我們上文提到的數據類型有關了,設備上線,心跳包回應等等。
事件又如何發送出去,通知到各個頁面呢?用 Listener、或者其他事件總線的三方庫都沒問題,看你自己選擇了。
處理接收的消息
理接收消息時,有幾個值得注意的點:
receive 方法是阻塞的,沒收到數據包時會一直阻塞,所以要放到子線程中;
每次接收到消息之后,重新調用 receivePacket.setLength;
收到消息刷新lastReceiveTime的值,暫停心跳包的發送;
處理收到的數據具體在業務上就是剛才我們談的發送數據的問題,視業務而定。
“用戶”的概念
上文已經談過了 UDP 的特性,假如一個手機已經開啟了熱點,若多個手機與他相連接,則多個手機發送的消息它都可以收到。如果發送方的端口與接收方的端口相同的話,甚至自己發的消息,自己都可以收到。這就很尷尬了,也就是說我們既要剔除自己發給自己的消息,也得區分不同手機發來的消息,這個時候就理應有一個“用戶”的概念。
創建 User 對象,有哪些屬性可以看自己的業務,本文的例子就有 ip、imei、以及 softversion。
這里就不將所有的代碼展開來看了。如果有了手機的 imei 號,那很容易就可以來做身份的區分,你既可以區分不同的發送方,也可以剔除掉自己發給自己的消息。當然如果需要更多的信息,可以按照自己的業務區分,將這些信息作為發送的 messge,通過 Socket 發送。
非常好我支持^.^
(0) 0%
不好我反對
(0) 0%
相關閱讀:
- [電子說] 社區說|多才多藝: 探索 Android 應用更多可能 2023-10-24
- [電子說] 浩辰軟件正式登陸上交所科創板 2023-10-23
- [電子說] 鴻蒙原生應用,對開發者意味著什么? 2023-10-22
- [電子說] Android端自定義鈴聲 MobPush對安卓端自定義鈴聲的教程 2023-10-21
- [電子說] Android推送問題排查技巧 針對MobPush安卓端推送問題的解決辦法 2023-10-21
- [電子說] 如何使用Proxyman抓取Android的https請求? 2023-10-19
- [編程語言及工具] 基于OkHttp 3.10.0的源碼案例解析 2023-10-17
- [電子說] 基于MacroBenchmark的性能測試量化指標方案 2023-10-17
( 發表人:黃昊宇 )