詳解OkSocket與Android的簡單使用
一個Android輕量級Socket通訊框架,既OkHttp后又一力作.
框架開源地址: https://github.com/xuuhaoo/OkSocket,歡迎star,fork,Issue交流
OkSocket簡介
Android OkSocket是一款基于阻塞式傳統(tǒng)Socket的一款Socket客戶端整體解決方案.您可以使用它進行簡單的基于Tcp協(xié)議的Socket通訊,當然,也可以進行大數(shù)據(jù)量復雜的Socket通訊,
支持單工,雙工通訊.
Maven配置
OkSocket 目前僅支持 JCenter 倉庫
allprojects {
repositories {
jcenter()
}
}
在Module的build.gradle文件中添加依賴配置
dependencies {
compile 'com.tonystark.android:socket:1.0.0'
}
參數(shù)配置
在AndroidManifest.xml中添加權限:
<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初始化
將以下代碼復制到項目Application類onCreate()中,OkSocket會為自動檢測環(huán)境并完成配置:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//在主進程初始化一次,多進程時需要區(qū)分主進程.
OkSocket.initialize(this);
//如果需要開啟Socket調試日志,請配置
//OkSocket.initialize(this,true);
}
}
調用演示
測試服務器
該服務器是專門為初學者調試 OkSocket 庫部屬的一臺測試服務器,初學者可以將項目中的 app 安裝到手機上,點擊 Connect 按鈕即可,該服務器僅為熟悉通訊方式和解析方式使用.該服務器不支持心跳返回,不能作為商用服務器.服務器代碼在 SocketServerDemo 文件夾中,請注意參考閱讀.
IP: 104.238.184.237
Port: 8080
您也可以選擇下載 JAR 文件到本地,運行在您的本地進行調試 Download JAR
下載后使用下面的代碼將其運行起來java -jar SocketServerDemo.jar
簡單的長連接
OkSocket 會默認對每一個 Open 的新通道做緩存管理,僅在第一次調用 Open 方法時創(chuàng)建 ConnectionManager 管理器,之后調用者可以通過獲取到該ConnectionManager的引用,繼續(xù)調用相關方法
ConnectionManager 主要負責該地址的套接字連接斷開發(fā)送消息等操作.
//連接參數(shù)設置(IP,端口號),這也是一個連接的唯一標識,不同連接,該參數(shù)中的兩個值至少有其一不一樣
ConnectionInfo info = new ConnectionInfo("104.238.184.237", 8080);
//調用OkSocket,開啟這次連接的通道,調用通道的連接方法進行連接.
OkSocket.open(info).connect();
有回調的長連接
注冊該通道的監(jiān)聽器,每個 Connection 通道中的監(jiān)聽器互相隔離,因此如果一個項目連接了多個 Socket 連接需要在每個 Connection 注冊自己的連接監(jiān)聽器,連接監(jiān)聽器是該 OkSocket 與用戶交互的唯一途徑
//連接參數(shù)設置(IP,端口號),這也是一個連接的唯一標識,不同連接,該參數(shù)中的兩個值至少有其一不一樣
ConnectionInfo info = new ConnectionInfo("104.238.184.237", 8080);
//調用OkSocket,開啟這次連接的通道,拿到通道Manager
IConnectionManager manager = OkSocket.open(info);
//注冊Socket行為監(jiān)聽器,SocketActionAdapter是回調的Simple類,其他回調方法請參閱類文檔
manager.registerReceiver(new SocketActionAdapter(){
@Override
public void onSocketConnectionSuccess(Context context, ConnectionInfo info, String action) {
Toast.makeText(context, "連接成功", LENGTH_SHORT).show();
}
});
//調用通道進行連接
manager.connect();
可配置的長連接
獲得 OkSocketOptions 的行為屬于比較高級的 OkSocket 調用方法,每個 Connection 將會對應一個 OkSocketOptions,如果第一次調用 Open 時未指定 OkSocketOptions,OkSocket將會使用默認的配置對象,默認配置請見文檔下方的高級調用說明
//連接參數(shù)設置(IP,端口號),這也是一個連接的唯一標識,不同連接,該參數(shù)中的兩個值至少有其一不一樣
ConnectionInfo info = new ConnectionInfo("104.238.184.237", 8080);
//調用OkSocket,開啟這次連接的通道,拿到通道Manager
IConnectionManager manager = OkSocket.open(info);
//獲得當前連接通道的參配對象
OkSocketOptions options= manager.getOption();
//基于當前參配對象構建一個參配建造者類
OkSocketOptions.Builder builder = new OkSocketOptions.Builder(options);
//修改參配設置(其他參配請參閱類文檔)
builder.setSinglePackageBytes(size);
//建造一個新的參配對象并且付給通道
manager.option(builder.build());
//調用通道進行連接
manager.connect();
如何進行數(shù)據(jù)發(fā)送
//類A:
//...定義將要發(fā)送的數(shù)據(jù)結構體...
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ù)服務器的解析規(guī)則,構建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;
//...省略連接及設置回調的代碼...
@Override
public void onSocketConnectionSuccess(Context context, ConnectionInfo info, String action) {
//連接成功其他操作...
//鏈式編程調用
OkSocket.open(info)
.send(new TestSendData());
//此處也可將ConnectManager保存成成員變量使用.
mManager = OkSocket.open(info);
if(mManager != null){
mManager.send(new TestSendData());
}
//以上兩種方法選擇其一,成員變量的方式請注意判空
}
如何接收數(shù)據(jù)
OkSocket客戶端接收服務器數(shù)據(jù)是要求一定格式的,客戶端的OkSocketOptions提供了接口來修改默認的服務器返回的包頭解析規(guī)則.請看下圖為默認的包頭包體解析規(guī)則

數(shù)據(jù)結構示意圖
如上圖包頭中的內容為4個字節(jié)長度的int型,該int值標識了包體數(shù)據(jù)區(qū)的長度,這就是默認的頭解析,如果需要自定義頭請按照如下方法.
//設置自定義解析頭
OkSocketOptions.Builder okOptionsBuilder = new OkSocketOptions.Builder(mOkOptions);
okOptionsBuilder.setHeaderProtocol(new IHeaderProtocol() {
@Override
public int getHeaderLength() {
//返回自定義的包頭長度,框架會解析該長度的包頭
return 0;
}
@Override
public int getBodyLength(byte[] header, ByteOrder byteOrder) {
//從header(包頭數(shù)據(jù))中解析出包體的長度,byteOrder是你在參配中配置的字節(jié)序,可以使用ByteBuffer比較方便解析
return 0;
}
});
//將新的修改后的參配設置給連接管理器
mManager.option(okOptionsBuilder.build());
//...正確設置解析頭之后...
@Override
public void onSocketReadResponse(Context context, ConnectionInfo info, String action, OriginalData data) {
//遵循以上規(guī)則,這個回調才可以正常收到服務器返回的數(shù)據(jù),數(shù)據(jù)在OriginalData中,為byte[]數(shù)組,該數(shù)組數(shù)據(jù)已經處理過字節(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;
//...省略連接及設置回調的代碼...
@Override
public void onSocketConnectionSuccess(Context context, ConnectionInfo info, String action) {
//連接成功其他操作...
//鏈式編程調用,給心跳管理器設置心跳數(shù)據(jù),一個連接只有一個心跳管理器,因此數(shù)據(jù)只用設置一次,如果斷開請再次設置.
OkSocket.open(info)
.getPulseManager()
.setPulseSendable(mPulseData)
.pulse();//開始心跳,開始心跳后,心跳管理器會自動進行心跳觸發(fā)
//此處也可將ConnectManager保存成成員變量使用.
mManager = OkSocket.open(info);
if(mManager != null){
PulseManager pulseManager = mManager.getPulseManager();
//給心跳管理器設置心跳數(shù)據(jù),一個連接只有一個心跳管理器,因此數(shù)據(jù)只用設置一次,如果斷開請再次設置.
pulseManager.setPulseSendable(mPulseData);
//開始心跳,開始心跳后,心跳管理器會自動進行心跳觸發(fā)
pulseManager.pulse();
}
//以上兩種方法選擇其一,成員變量的方式請注意判空
}
心跳接收到了之后需要進行喂狗
因為我們的客戶端需要知道服務器收到了此次心跳,因此服務器在收到心跳后需要進行應答,我們收到此次心跳應答后,需要進行本地的喂狗操作,否則當超過一定次數(shù)的心跳發(fā)送,未得到喂狗操作后,狗將會將此次連接斷開重連.
//定義成員變量
private IConnectionManager mManager;
//當客戶端收到消息后
@Override
public void onSocketReadResponse(Context context, ConnectionInfo info, String action, OriginalData data) {
if(mManager != null && 是心跳返回包){//是否是心跳返回包,需要解析服務器返回的數(shù)據(jù)才可知道
//喂狗操作
mManager.getPulseManager().feed();
}
}
如何手動觸發(fā)一次心跳,在任何時間
//定義成員變量
private IConnectionManager mManager;
//...在任意地方...
mManager = OkSocket.open(info);
if(mManager != null){
PulseManager pulseManager = mManager.getPulseManager();
//手動觸發(fā)一次心跳(主要用于一些需要手動控制觸發(fā)時機的場景)
pulseManager.trigger();
}
OkSocket參配選項及回調說明
OkSocketOptions
- Socket通訊模式mIOThreadMode
- 連接是否管理保存isConnectionHolden
- 寫入字節(jié)序mWriteOrder
- 讀取字節(jié)序mReadByteOrder
- 頭字節(jié)協(xié)議mHeaderProtocol
- 發(fā)送單個數(shù)據(jù)包的總長度mSendSinglePackageBytes
- 單次讀取的緩存字節(jié)長度mReadSingleTimeBufferBytes
- 脈搏頻率間隔毫秒數(shù)mPulseFrequency
- 脈搏最大丟失次數(shù)(狗的失喂次數(shù))mPulseFeedLoseTimes
- 后臺存活時間(分鐘)mBackgroundLiveMinute
- 連接超時時間(秒)mConnectTimeoutSecond
- 最大讀取數(shù)據(jù)的兆數(shù)(MB)mMaxReadDataMB
- 重新連接管理器mReconnectionManager
ISocketActionListener
- Socket讀寫線程啟動后回調onSocketIOThreadStart
- Socket讀寫線程關閉后回調onSocketIOThreadShutdown
- Socket連接狀態(tài)由連接->斷開回調onSocketDisconnection
- Socket連接成功回調onSocketConnectionSuccess
- Socket連接失敗回調onSocketConnectionFailed
- Socket從服務器讀取到字節(jié)回調onSocketReadResponse
- Socket寫給服務器字節(jié)后回調onSocketWriteResponse
- 發(fā)送心跳后的回調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.
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
- 詳解Android 基于TCP和UDP協(xié)議的Socket通信
- Android使用WebSocket實現(xiàn)多人游戲
- Android開發(fā)之Socket通信傳輸簡單示例
- android基于socket的局域網內服務器與客戶端加密通信
- android socket聊天室功能實現(xiàn)
- SpringBoot webSocket實現(xiàn)發(fā)送廣播、點對點消息和Android接收
- Android中Socket大文件斷點上傳示例
- android Socket實現(xiàn)簡單聊天功能以及文件傳輸
- 詳解Android使用Socket對大文件進行加密傳輸
- 詳解Android 通過Socket 和服務器通訊(附demo)
- Android Socket接口實現(xiàn)即時通訊實例代碼
- Android完整Socket解決方案
相關文章
android TextView多行文本(超過3行)使用ellipsize屬性無效問題的解決方法
這篇文章介紹了android TextView多行文本(超過3行)使用ellipsize屬性無效問題的解決方法,有需要的朋友可以參考一下2013-09-09
Android TextView使用SpannableString設置復合文本的方法詳解
這篇文章主要介紹了Android TextView使用SpannableString設置復合文本的方法,結合實例形式詳細分析了Android中SpannableString類的功能及相關用法,需要的朋友可以參考下2016-08-08
Android Studio使用ViewPager+Fragment實現(xiàn)滑動菜單Tab效果
這篇文章主要為大家詳細介紹了Android Studio使用ViewPager+Fragment實現(xiàn)滑動菜單Tab效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-09-09
Android事件分發(fā)機制(下) View的事件處理
這篇文章主要介紹了Android事件分發(fā)機制下篇, View的事件處理的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-01-01
Android開發(fā)全局音量調整的實現(xiàn)方式詳解
這篇文章主要為大家介紹了Android開發(fā)全局音量調整的實現(xiàn)方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11

