詳解OkSocket與Android的簡單使用
一個(gè)Android輕量級(jí)Socket通訊框架,既OkHttp后又一力作.
框架開源地址: https://github.com/xuuhaoo/OkSocket,歡迎star,fork,Issue交流
OkSocket簡介
Android OkSocket是一款基于阻塞式傳統(tǒng)Socket的一款Socket客戶端整體解決方案.您可以使用它進(jìn)行簡單的基于Tcp協(xié)議的Socket通訊,當(dāng)然,也可以進(jìn)行大數(shù)據(jù)量復(fù)雜的Socket通訊,
支持單工,雙工通訊.
Maven配置
OkSocket 目前僅支持 JCenter 倉庫
allprojects { repositories { jcenter() } }
在Module的build.gradle文件中添加依賴配置
dependencies { compile 'com.tonystark.android:socket:1.0.0' }
參數(shù)配置
在AndroidManifest.xml中添加權(quán)限:
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
混淆配置
請避免混淆OkSocket,在Proguard混淆文件中增加以下配置:
-dontwarn com.xuhao.android.libsocket.** -keep class com.xuhao.android.socket.impl.abilities.** { *; } -keep class com.xuhao.android.socket.impl.exceptions.** { *; } -keep class com.xuhao.android.socket.impl.EnvironmentalManager { *; } -keep class com.xuhao.android.socket.impl.BlockConnectionManager { *; } -keep class com.xuhao.android.socket.impl.UnBlockConnectionManager { *; } -keep class com.xuhao.android.socket.impl.SocketActionHandler { *; } -keep class com.xuhao.android.socket.impl.PulseManager { *; } -keep class com.xuhao.android.socket.impl.ManagerHolder { *; } -keep class com.xuhao.android.socket.interfaces.** { *; } -keep class com.xuhao.android.socket.sdk.** { *; } # 枚舉類不能被混淆 -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); } -keep class com.xuhao.android.socket.sdk.OkSocketOptions$* { *; }
OkSocket初始化
將以下代碼復(fù)制到項(xiàng)目Application類onCreate()中,OkSocket會(huì)為自動(dòng)檢測環(huán)境并完成配置:
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); //在主進(jìn)程初始化一次,多進(jìn)程時(shí)需要區(qū)分主進(jìn)程. OkSocket.initialize(this); //如果需要開啟Socket調(diào)試日志,請配置 //OkSocket.initialize(this,true); } }
調(diào)用演示
測試服務(wù)器
該服務(wù)器是專門為初學(xué)者調(diào)試 OkSocket 庫部屬的一臺(tái)測試服務(wù)器,初學(xué)者可以將項(xiàng)目中的 app 安裝到手機(jī)上,點(diǎn)擊 Connect 按鈕即可,該服務(wù)器僅為熟悉通訊方式和解析方式使用.該服務(wù)器不支持心跳返回,不能作為商用服務(wù)器.服務(wù)器代碼在 SocketServerDemo 文件夾中,請注意參考閱讀.
IP: 104.238.184.237
Port: 8080
您也可以選擇下載 JAR 文件到本地,運(yùn)行在您的本地進(jìn)行調(diào)試 Download JAR
下載后使用下面的代碼將其運(yùn)行起來java -jar SocketServerDemo.jar
簡單的長連接
OkSocket 會(huì)默認(rèn)對每一個(gè) Open 的新通道做緩存管理,僅在第一次調(diào)用 Open 方法時(shí)創(chuàng)建 ConnectionManager 管理器,之后調(diào)用者可以通過獲取到該ConnectionManager的引用,繼續(xù)調(diào)用相關(guān)方法
ConnectionManager 主要負(fù)責(zé)該地址的套接字連接斷開發(fā)送消息等操作. //連接參數(shù)設(shè)置(IP,端口號(hào)),這也是一個(gè)連接的唯一標(biāo)識(shí),不同連接,該參數(shù)中的兩個(gè)值至少有其一不一樣 ConnectionInfo info = new ConnectionInfo("104.238.184.237", 8080); //調(diào)用OkSocket,開啟這次連接的通道,調(diào)用通道的連接方法進(jìn)行連接. OkSocket.open(info).connect();
有回調(diào)的長連接
注冊該通道的監(jiān)聽器,每個(gè) Connection 通道中的監(jiān)聽器互相隔離,因此如果一個(gè)項(xiàng)目連接了多個(gè) Socket 連接需要在每個(gè) Connection 注冊自己的連接監(jiān)聽器,連接監(jiān)聽器是該 OkSocket 與用戶交互的唯一途徑
//連接參數(shù)設(shè)置(IP,端口號(hào)),這也是一個(gè)連接的唯一標(biāo)識(shí),不同連接,該參數(shù)中的兩個(gè)值至少有其一不一樣 ConnectionInfo info = new ConnectionInfo("104.238.184.237", 8080); //調(diào)用OkSocket,開啟這次連接的通道,拿到通道Manager IConnectionManager manager = OkSocket.open(info); //注冊Socket行為監(jiān)聽器,SocketActionAdapter是回調(diào)的Simple類,其他回調(diào)方法請參閱類文檔 manager.registerReceiver(new SocketActionAdapter(){ @Override public void onSocketConnectionSuccess(Context context, ConnectionInfo info, String action) { Toast.makeText(context, "連接成功", LENGTH_SHORT).show(); } }); //調(diào)用通道進(jìn)行連接 manager.connect();
可配置的長連接
獲得 OkSocketOptions 的行為屬于比較高級(jí)的 OkSocket 調(diào)用方法,每個(gè) Connection 將會(huì)對應(yīng)一個(gè) OkSocketOptions,如果第一次調(diào)用 Open 時(shí)未指定 OkSocketOptions,OkSocket將會(huì)使用默認(rèn)的配置對象,默認(rèn)配置請見文檔下方的高級(jí)調(diào)用說明
//連接參數(shù)設(shè)置(IP,端口號(hào)),這也是一個(gè)連接的唯一標(biāo)識(shí),不同連接,該參數(shù)中的兩個(gè)值至少有其一不一樣 ConnectionInfo info = new ConnectionInfo("104.238.184.237", 8080); //調(diào)用OkSocket,開啟這次連接的通道,拿到通道Manager IConnectionManager manager = OkSocket.open(info); //獲得當(dāng)前連接通道的參配對象 OkSocketOptions options= manager.getOption(); //基于當(dāng)前參配對象構(gòu)建一個(gè)參配建造者類 OkSocketOptions.Builder builder = new OkSocketOptions.Builder(options); //修改參配設(shè)置(其他參配請參閱類文檔) builder.setSinglePackageBytes(size); //建造一個(gè)新的參配對象并且付給通道 manager.option(builder.build()); //調(diào)用通道進(jìn)行連接 manager.connect();
如何進(jìn)行數(shù)據(jù)發(fā)送
//類A: //...定義將要發(fā)送的數(shù)據(jù)結(jié)構(gòu)體... public class TestSendData implements ISendable { private String str = ""; public TestSendData() { JSONObject jsonObject = new JSONObject(); try { jsonObject.put("cmd", 14); jsonObject.put("data", "{x:2,y:1}"); str = jsonObject.toString(); } catch (JSONException e) { e.printStackTrace(); } } @Override public byte[] parse() { //根據(jù)服務(wù)器的解析規(guī)則,構(gòu)建byte數(shù)組 byte[] body = str.getBytes(Charset.defaultCharset()); ByteBuffer bb = ByteBuffer.allocate(4 + body.length); bb.order(ByteOrder.BIG_ENDIAN); bb.putInt(body.length); bb.put(body); return bb.array(); } } //類B: private IConnectionManager mManager; //...省略連接及設(shè)置回調(diào)的代碼... @Override public void onSocketConnectionSuccess(Context context, ConnectionInfo info, String action) { //連接成功其他操作... //鏈?zhǔn)骄幊陶{(diào)用 OkSocket.open(info) .send(new TestSendData()); //此處也可將ConnectManager保存成成員變量使用. mManager = OkSocket.open(info); if(mManager != null){ mManager.send(new TestSendData()); } //以上兩種方法選擇其一,成員變量的方式請注意判空 }
如何接收數(shù)據(jù)
OkSocket客戶端接收服務(wù)器數(shù)據(jù)是要求一定格式的,客戶端的OkSocketOptions提供了接口來修改默認(rèn)的服務(wù)器返回的包頭解析規(guī)則.請看下圖為默認(rèn)的包頭包體解析規(guī)則
數(shù)據(jù)結(jié)構(gòu)示意圖
如上圖包頭中的內(nèi)容為4個(gè)字節(jié)長度的int型,該int值標(biāo)識(shí)了包體數(shù)據(jù)區(qū)的長度,這就是默認(rèn)的頭解析,如果需要自定義頭請按照如下方法.
//設(shè)置自定義解析頭 OkSocketOptions.Builder okOptionsBuilder = new OkSocketOptions.Builder(mOkOptions); okOptionsBuilder.setHeaderProtocol(new IHeaderProtocol() { @Override public int getHeaderLength() { //返回自定義的包頭長度,框架會(huì)解析該長度的包頭 return 0; } @Override public int getBodyLength(byte[] header, ByteOrder byteOrder) { //從header(包頭數(shù)據(jù))中解析出包體的長度,byteOrder是你在參配中配置的字節(jié)序,可以使用ByteBuffer比較方便解析 return 0; } }); //將新的修改后的參配設(shè)置給連接管理器 mManager.option(okOptionsBuilder.build()); //...正確設(shè)置解析頭之后... @Override public void onSocketReadResponse(Context context, ConnectionInfo info, String action, OriginalData data) { //遵循以上規(guī)則,這個(gè)回調(diào)才可以正常收到服務(wù)器返回的數(shù)據(jù),數(shù)據(jù)在OriginalData中,為byte[]數(shù)組,該數(shù)組數(shù)據(jù)已經(jīng)處理過字節(jié)序問題,直接放入ByteBuffer中即可使用 }
如何保持心跳
//類A: //...定義心跳管理器需要的心跳數(shù)據(jù)類型... public class PulseData implements IPulseSendable { private String str = "pulse"; @Override public byte[] parse() { byte[] body = str.getBytes(Charset.defaultCharset()); ByteBuffer bb = ByteBuffer.allocate(4 + body.length); bb.order(ByteOrder.BIG_ENDIAN); bb.putInt(body.length); bb.put(body); return bb.array(); } } //類B: private IConnectionManager mManager; private PulseData mPulseData = new PulseData; //...省略連接及設(shè)置回調(diào)的代碼... @Override public void onSocketConnectionSuccess(Context context, ConnectionInfo info, String action) { //連接成功其他操作... //鏈?zhǔn)骄幊陶{(diào)用,給心跳管理器設(shè)置心跳數(shù)據(jù),一個(gè)連接只有一個(gè)心跳管理器,因此數(shù)據(jù)只用設(shè)置一次,如果斷開請?jiān)俅卧O(shè)置. OkSocket.open(info) .getPulseManager() .setPulseSendable(mPulseData) .pulse();//開始心跳,開始心跳后,心跳管理器會(huì)自動(dòng)進(jìn)行心跳觸發(fā) //此處也可將ConnectManager保存成成員變量使用. mManager = OkSocket.open(info); if(mManager != null){ PulseManager pulseManager = mManager.getPulseManager(); //給心跳管理器設(shè)置心跳數(shù)據(jù),一個(gè)連接只有一個(gè)心跳管理器,因此數(shù)據(jù)只用設(shè)置一次,如果斷開請?jiān)俅卧O(shè)置. pulseManager.setPulseSendable(mPulseData); //開始心跳,開始心跳后,心跳管理器會(huì)自動(dòng)進(jìn)行心跳觸發(fā) pulseManager.pulse(); } //以上兩種方法選擇其一,成員變量的方式請注意判空 }
心跳接收到了之后需要進(jìn)行喂狗
因?yàn)槲覀兊目蛻舳诵枰婪?wù)器收到了此次心跳,因此服務(wù)器在收到心跳后需要進(jìn)行應(yīng)答,我們收到此次心跳應(yīng)答后,需要進(jìn)行本地的喂狗操作,否則當(dāng)超過一定次數(shù)的心跳發(fā)送,未得到喂狗操作后,狗將會(huì)將此次連接斷開重連.
//定義成員變量 private IConnectionManager mManager; //當(dāng)客戶端收到消息后 @Override public void onSocketReadResponse(Context context, ConnectionInfo info, String action, OriginalData data) { if(mManager != null && 是心跳返回包){//是否是心跳返回包,需要解析服務(wù)器返回的數(shù)據(jù)才可知道 //喂狗操作 mManager.getPulseManager().feed(); } }
如何手動(dòng)觸發(fā)一次心跳,在任何時(shí)間
//定義成員變量 private IConnectionManager mManager; //...在任意地方... mManager = OkSocket.open(info); if(mManager != null){ PulseManager pulseManager = mManager.getPulseManager(); //手動(dòng)觸發(fā)一次心跳(主要用于一些需要手動(dòng)控制觸發(fā)時(shí)機(jī)的場景) pulseManager.trigger(); }
OkSocket參配選項(xiàng)及回調(diào)說明
OkSocketOptions
- Socket通訊模式mIOThreadMode
- 連接是否管理保存isConnectionHolden
- 寫入字節(jié)序mWriteOrder
- 讀取字節(jié)序mReadByteOrder
- 頭字節(jié)協(xié)議mHeaderProtocol
- 發(fā)送單個(gè)數(shù)據(jù)包的總長度mSendSinglePackageBytes
- 單次讀取的緩存字節(jié)長度mReadSingleTimeBufferBytes
- 脈搏頻率間隔毫秒數(shù)mPulseFrequency
- 脈搏最大丟失次數(shù)(狗的失喂次數(shù))mPulseFeedLoseTimes
- 后臺(tái)存活時(shí)間(分鐘)mBackgroundLiveMinute
- 連接超時(shí)時(shí)間(秒)mConnectTimeoutSecond
- 最大讀取數(shù)據(jù)的兆數(shù)(MB)mMaxReadDataMB
- 重新連接管理器mReconnectionManager
ISocketActionListener
- Socket讀寫線程啟動(dòng)后回調(diào)onSocketIOThreadStart
- Socket讀寫線程關(guān)閉后回調(diào)onSocketIOThreadShutdown
- Socket連接狀態(tài)由連接->斷開回調(diào)onSocketDisconnection
- Socket連接成功回調(diào)onSocketConnectionSuccess
- Socket連接失敗回調(diào)onSocketConnectionFailed
- Socket從服務(wù)器讀取到字節(jié)回調(diào)onSocketReadResponse
- Socket寫給服務(wù)器字節(jié)后回調(diào)onSocketWriteResponse
- 發(fā)送心跳后的回調(diào)onPulseSend
Copyright [2017] [徐昊] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 詳解Android 基于TCP和UDP協(xié)議的Socket通信
- Android使用WebSocket實(shí)現(xiàn)多人游戲
- Android開發(fā)之Socket通信傳輸簡單示例
- android基于socket的局域網(wǎng)內(nèi)服務(wù)器與客戶端加密通信
- android socket聊天室功能實(shí)現(xiàn)
- SpringBoot webSocket實(shí)現(xiàn)發(fā)送廣播、點(diǎn)對點(diǎn)消息和Android接收
- Android中Socket大文件斷點(diǎn)上傳示例
- android Socket實(shí)現(xiàn)簡單聊天功能以及文件傳輸
- 詳解Android使用Socket對大文件進(jìn)行加密傳輸
- 詳解Android 通過Socket 和服務(wù)器通訊(附demo)
- Android Socket接口實(shí)現(xiàn)即時(shí)通訊實(shí)例代碼
- Android完整Socket解決方案
相關(guān)文章
Android webview轉(zhuǎn)PDF的方法示例
本篇文章主要介紹了Android webview轉(zhuǎn)PDF的方法示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-01-01Android編程之線性布局LinearLayout實(shí)例簡析
這篇文章主要介紹了Android編程之線性布局LinearLayout用法,結(jié)合實(shí)例形式簡單分析了Android線性布局的使用技巧,需要的朋友可以參考下2016-01-01簡單介紹Android開發(fā)中的Activity控件的基本概念
這篇文章主要介紹了Android開發(fā)中的Activity控件的基本概念,Activity控件的使用是安卓開發(fā)的基礎(chǔ)之一,需要的朋友可以參考下2015-12-12Android RecyclerView滑動(dòng)刪除和拖動(dòng)排序
這篇文章主要介紹了Android RecyclerView滑動(dòng)刪除和拖動(dòng)排序的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-07-07android 處理配置變更的實(shí)現(xiàn)方法
這篇文章主要介紹了android 處理配置變更的實(shí)現(xiàn)方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-07-07舉例講解Android應(yīng)用中SimpleAdapter簡單適配器的使用
這篇文章主要介紹了Android應(yīng)用中SimpleAdapter簡單適配器的使用例子,SimpleAdapter經(jīng)常在ListView被使用,需要的朋友可以參考下2016-04-04