詳解OkSocket與Android的簡單使用
一個Android輕量級Socket通訊框架,既OkHttp后又一力作.
框架開源地址: https://github.com/xuuhaoo/OkSocket,歡迎star,fork,Issue交流
OkSocket簡介
Android OkSocket是一款基于阻塞式傳統(tǒng)Socket的一款Socket客戶端整體解決方案.您可以使用它進行簡單的基于Tcp協(xié)議的Socket通訊,當(dāng)然,也可以進行大數(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ù)制到項目Application類onCreate()中,OkSocket會為自動檢測環(huán)境并完成配置:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//在主進程初始化一次,多進程時需要區(qū)分主進程.
OkSocket.initialize(this);
//如果需要開啟Socket調(diào)試日志,請配置
//OkSocket.initialize(this,true);
}
}
調(diào)用演示
測試服務(wù)器
該服務(wù)器是專門為初學(xué)者調(diào)試 OkSocket 庫部屬的一臺測試服務(wù)器,初學(xué)者可以將項目中的 app 安裝到手機上,點擊 Connect 按鈕即可,該服務(wù)器僅為熟悉通訊方式和解析方式使用.該服務(wù)器不支持心跳返回,不能作為商用服務(wù)器.服務(wù)器代碼在 SocketServerDemo 文件夾中,請注意參考閱讀.
IP: 104.238.184.237
Port: 8080
您也可以選擇下載 JAR 文件到本地,運行在您的本地進行調(diào)試 Download JAR
下載后使用下面的代碼將其運行起來java -jar SocketServerDemo.jar
簡單的長連接
OkSocket 會默認(rèn)對每一個 Open 的新通道做緩存管理,僅在第一次調(diào)用 Open 方法時創(chuàng)建 ConnectionManager 管理器,之后調(diào)用者可以通過獲取到該ConnectionManager的引用,繼續(xù)調(diào)用相關(guān)方法
ConnectionManager 主要負(fù)責(zé)該地址的套接字連接斷開發(fā)送消息等操作.
//連接參數(shù)設(shè)置(IP,端口號),這也是一個連接的唯一標(biāo)識,不同連接,該參數(shù)中的兩個值至少有其一不一樣
ConnectionInfo info = new ConnectionInfo("104.238.184.237", 8080);
//調(diào)用OkSocket,開啟這次連接的通道,調(diào)用通道的連接方法進行連接.
OkSocket.open(info).connect();
有回調(diào)的長連接
注冊該通道的監(jiān)聽器,每個 Connection 通道中的監(jiān)聽器互相隔離,因此如果一個項目連接了多個 Socket 連接需要在每個 Connection 注冊自己的連接監(jiān)聽器,連接監(jiān)聽器是該 OkSocket 與用戶交互的唯一途徑
//連接參數(shù)設(shè)置(IP,端口號),這也是一個連接的唯一標(biāo)識,不同連接,該參數(shù)中的兩個值至少有其一不一樣
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)用通道進行連接
manager.connect();
可配置的長連接
獲得 OkSocketOptions 的行為屬于比較高級的 OkSocket 調(diào)用方法,每個 Connection 將會對應(yīng)一個 OkSocketOptions,如果第一次調(diào)用 Open 時未指定 OkSocketOptions,OkSocket將會使用默認(rèn)的配置對象,默認(rèn)配置請見文檔下方的高級調(diào)用說明
//連接參數(shù)設(shè)置(IP,端口號),這也是一個連接的唯一標(biāo)識,不同連接,該參數(shù)中的兩個值至少有其一不一樣
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)建一個參配建造者類
OkSocketOptions.Builder builder = new OkSocketOptions.Builder(options);
//修改參配設(shè)置(其他參配請參閱類文檔)
builder.setSinglePackageBytes(size);
//建造一個新的參配對象并且付給通道
manager.option(builder.build());
//調(diào)用通道進行連接
manager.connect();
如何進行數(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個字節(jié)長度的int型,該int值標(biāo)識了包體數(shù)據(jù)區(qū)的長度,這就是默認(rèn)的頭解析,如果需要自定義頭請按照如下方法.
//設(shè)置自定義解析頭
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;
}
});
//將新的修改后的參配設(shè)置給連接管理器
mManager.option(okOptionsBuilder.build());
//...正確設(shè)置解析頭之后...
@Override
public void onSocketReadResponse(Context context, ConnectionInfo info, String action, OriginalData data) {
//遵循以上規(guī)則,這個回調(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ù),一個連接只有一個心跳管理器,因此數(shù)據(jù)只用設(shè)置一次,如果斷開請再次設(shè)置.
OkSocket.open(info)
.getPulseManager()
.setPulseSendable(mPulseData)
.pulse();//開始心跳,開始心跳后,心跳管理器會自動進行心跳觸發(fā)
//此處也可將ConnectManager保存成成員變量使用.
mManager = OkSocket.open(info);
if(mManager != null){
PulseManager pulseManager = mManager.getPulseManager();
//給心跳管理器設(shè)置心跳數(shù)據(jù),一個連接只有一個心跳管理器,因此數(shù)據(jù)只用設(shè)置一次,如果斷開請再次設(shè)置.
pulseManager.setPulseSendable(mPulseData);
//開始心跳,開始心跳后,心跳管理器會自動進行心跳觸發(fā)
pulseManager.pulse();
}
//以上兩種方法選擇其一,成員變量的方式請注意判空
}
心跳接收到了之后需要進行喂狗
因為我們的客戶端需要知道服務(wù)器收到了此次心跳,因此服務(wù)器在收到心跳后需要進行應(yīng)答,我們收到此次心跳應(yīng)答后,需要進行本地的喂狗操作,否則當(dāng)超過一定次數(shù)的心跳發(fā)送,未得到喂狗操作后,狗將會將此次連接斷開重連.
//定義成員變量
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();
}
}
如何手動觸發(fā)一次心跳,在任何時間
//定義成員變量
private IConnectionManager mManager;
//...在任意地方...
mManager = OkSocket.open(info);
if(mManager != null){
PulseManager pulseManager = mManager.getPulseManager();
//手動觸發(fā)一次心跳(主要用于一些需要手動控制觸發(fā)時機的場景)
pulseManager.trigger();
}
OkSocket參配選項及回調(diào)說明
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讀寫線程啟動后回調(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實現(xiàn)多人游戲
- Android開發(fā)之Socket通信傳輸簡單示例
- android基于socket的局域網(wǎng)內(nèi)服務(wù)器與客戶端加密通信
- android socket聊天室功能實現(xiàn)
- SpringBoot webSocket實現(xiàn)發(fā)送廣播、點對點消息和Android接收
- Android中Socket大文件斷點上傳示例
- android Socket實現(xiàn)簡單聊天功能以及文件傳輸
- 詳解Android使用Socket對大文件進行加密傳輸
- 詳解Android 通過Socket 和服務(wù)器通訊(附demo)
- Android Socket接口實現(xiàn)即時通訊實例代碼
- Android完整Socket解決方案
相關(guān)文章
Android webview轉(zhuǎn)PDF的方法示例
本篇文章主要介紹了Android webview轉(zhuǎn)PDF的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01
Android編程之線性布局LinearLayout實例簡析
這篇文章主要介紹了Android編程之線性布局LinearLayout用法,結(jié)合實例形式簡單分析了Android線性布局的使用技巧,需要的朋友可以參考下2016-01-01
簡單介紹Android開發(fā)中的Activity控件的基本概念
這篇文章主要介紹了Android開發(fā)中的Activity控件的基本概念,Activity控件的使用是安卓開發(fā)的基礎(chǔ)之一,需要的朋友可以參考下2015-12-12
舉例講解Android應(yīng)用中SimpleAdapter簡單適配器的使用
這篇文章主要介紹了Android應(yīng)用中SimpleAdapter簡單適配器的使用例子,SimpleAdapter經(jīng)常在ListView被使用,需要的朋友可以參考下2016-04-04

