Android-TCP客戶端的實現
前言
因為需求,可能需要在安卓上完成一個同時包含UDP和TCP的專案。因此,本來做iOS的小編在閒暇之餘,研究了一波安卓的TCP客戶端是如何實現的。
UDP客戶端實現請點這裡:UDP。
實現
小編看了很多資料,發現網上的資料大多數很複雜,並不能滿足小編最基礎的需求。因此,小編決定自己封裝一個簡易的類來方便使用。
建立單例
首先,小編想到的是單例。因為不管是iOS還是安卓,都應該有單例。單例的好處主要在於可以使該類在系統記憶體中只存在一個物件,可以節約系統資源,對於一些需要頻繁建立和銷燬的物件,可以明顯的提高系統的效能。
安卓的單例寫法有很多種,最後小編選擇了一種自己認為比較好的寫法,如下:
public class TaskCenter {
private static TaskCenter instance;
// 建構函式私有化
private TaskCenter() {
super();
}
// 提供一個全域性的靜態方法
public static TaskCenter sharedCenter() {
if (instance == null) {
synchronized (TaskCenter.class) {
if (instance == null) {
instance = new TaskCenter();
}
}
}
return instance;
}
建立執行緒
為了能更好的處理資料,小編在這裡建立了一個執行緒,在TCP連線時啟動。如下:
private static final String TAG = "TaskCenter";
// Socket
private Socket socket;
// IP地址
private String ipAddress;
// 埠號
private int port;
// 執行緒
private Thread thread;
// Socket輸出流
private OutputStream outputStream;
// Socket輸入流
private InputStream inputStream;
-------------------------------------------------------------------
/**
* 通過IP地址(域名)和埠進行連線
*
* @param ipAddress IP地址(域名)
* @param port 埠
*/
public void connect(final String ipAddress, final int port) {
thread = new Thread(new Runnable() {
@Override
public void run() {
try {
socket = new Socket(ipAddress, port);
// socket.setSoTimeout ( 2 * 1000 );//設定超時時間
if (isConnected()) {
TaskCenter.sharedCenter().ipAddress = ipAddress;
TaskCenter.sharedCenter().port = port;
if (connectedCallback != null) {
connectedCallback.callback();
}
outputStream = socket.getOutputStream();
inputStream = socket.getInputStream();
receive();
Log.i(TAG,"連線成功");
}else {
Log.i(TAG,"連線失敗");
if (disconnectedCallback != null) {
disconnectedCallback.callback(new IOException("連線失敗"));
}
}
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG,"連線異常");
if (disconnectedCallback != null) {
disconnectedCallback.callback(e);
}
}
}
});
thread.start();
}
TCP傳送和接收的整合
整合的思路是開啟執行緒,建立一個方法去初始化socket,初始化完後,並線上程中加入接收資料的方法。如下:
/**
* 接收資料
*/
public void receive() {
while (isConnected()) {
try {
/**得到的是16進位制數,需要進行解析*/
byte[] bt = new byte[1024];
// 獲取接收到的位元組和位元組數
int length = inputStream.read(bt);
// 獲取正確的位元組
byte[] bs = new byte[length];
System.arraycopy(bt, 0, bs, 0, length);
String str = new String(bs, "UTF-8");
if (str != null) {
if (receivedCallback != null) {
receivedCallback.callback(str);
}
}
Log.i(TAG,"接收成功");
} catch (IOException e) {
Log.i(TAG,"接收失敗");
}
}
}
/**
* 傳送資料
*
* @param data 資料
*/
public void send(final byte[] data) {
new Thread(new Runnable() {
@Override
public void run() {
if (socket != null) {
try {
outputStream.write(data);
outputStream.flush();
Log.i(TAG,"傳送成功");
} catch (IOException e) {
e.printStackTrace();
Log.i(TAG,"傳送失敗");
}
} else {
connect();
}
}
}).start();
}
在接收到資料包之後需要將資料回撥出去,但是網上大多數都是把控制器在類中,這不是小編的初衷。因此小編用了一種類似iOS中Block的方式去回撥。如下:
// 連線回撥
private OnServerConnectedCallbackBlock connectedCallback;
// 斷開連線回撥(連線失敗)
private OnServerDisconnectedCallbackBlock disconnectedCallback;
// 接收資訊回撥
private OnReceiveCallbackBlock receivedCallback;
-------------------------------------------------------------------
/**
* 回撥宣告
*/
public interface OnServerConnectedCallbackBlock {
void callback();
}
public interface OnServerDisconnectedCallbackBlock {
void callback(IOException e);
}
public interface OnReceiveCallbackBlock {
void callback(String receicedMessage);
}
public void setConnectedCallback(OnServerConnectedCallbackBlock connectedCallback) {
this.connectedCallback = connectedCallback;
}
public void setDisconnectedCallback(OnServerDisconnectedCallbackBlock disconnectedCallback) {
this.disconnectedCallback = disconnectedCallback;
}
public void setReceivedCallback(OnReceiveCallbackBlock receivedCallback) {
this.receivedCallback = receivedCallback;
}
/**
* 移除回撥
*/
private void removeCallback() {
connectedCallback = null;
disconnectedCallback = null;
receivedCallback = null;
}
既然有開啟TCP,那肯定有關閉TCP的時候,關閉TCO時需要接收資訊的回撥和執行緒也移除。注意:在接收包時,有可能因為socket原因而接收失敗,此時也需要關閉。這裡並不影響下次傳送,因為下次傳送時會判斷socket存不存在,不存在會重新建立。如下:
/**
* 斷開連線
*/
public void disconnect() {
if (isConnected()) {
try {
if (outputStream != null) {
outputStream.close();
}
socket.close();
if (socket.isClosed()) {
if (disconnectedCallback != null) {
disconnectedCallback.callback(new IOException("斷開連線"));
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
到這裡,就整合完成了。
3.使用
使用起來相當簡單,匯入類,初始化,通過該類的方法傳送資訊和接收資訊即可,如下:
TaskCenter.sharedCenter().setDisconnectedCallback(new TaskCenter.OnServerDisconnectedCallbackBlock() {
@Override
public void callback(IOException e) {
textView_receive.setText(textView_receive.getText().toString() + "斷開連線" + "\n");
}
});
TaskCenter.sharedCenter().setConnectedCallback(new TaskCenter.OnServerConnectedCallbackBlock() {
@Override
public void callback() {
textView_receive.setText(textView_receive.getText().toString() + "連線成功" + "\n");
}
});
TaskCenter.sharedCenter().setReceivedCallback(new TaskCenter.OnReceiveCallbackBlock() {
@Override
public void callback(String receicedMessage) {
textView_receive.setText(textView_receive.getText().toString() + receicedMessage + "\n");
}
});
-----------------------------------------------------------------------
//連線
TaskCenter.sharedCenter().connect("xxx.xxx.xx.xxxx",xxxx);
//傳送
TaskCenter.sharedCenter().send(msg.getBytes());
斷開連線
TaskCenter.sharedCenter().disconnect();
到這裡為止,TCP客戶端的Demo就完成了,寫的不好的地方歡迎大家指出,Demo下載地址:Demo。最後,希望這篇文章對各位看官們有所幫助。
相關文章
- 客戶端骨架屏實現客戶端
- Redis的Pub/Sub客戶端實現Redis客戶端
- 網頁SSH客戶端的實現網頁客戶端
- jQuery實現客戶端CheckAll功能jQuery客戶端
- Go 實現簡易的 Redis 客戶端GoRedis客戶端
- golang實現tcp客戶端服務端程式GolangTCP客戶端服務端
- c#實現redis客戶端(一)C#Redis客戶端
- 實現客戶端與服務端的HTTP通訊客戶端服務端HTTP
- Istio 中實現客戶端源 IP 的保持客戶端
- pycurl實現hadoop的客戶端功能薦Hadoop客戶端
- Android實現Thrift服務端與客戶端Android服務端客戶端
- Redis 6.0 客戶端快取的伺服器端實現Redis客戶端快取伺服器
- IM撤回訊息-iOS客戶端實現iOS客戶端
- FTP客戶端c程式碼功能實現FTP客戶端C程式
- Vue實現騰訊視訊Mac客戶端VueMac客戶端
- 實現客戶端加密,後臺解密薦客戶端加密解密
- 03. 實現客戶端應用程式客戶端
- Java的oauth2.0 服務端與客戶端的實現JavaOAuth服務端客戶端
- 使用 Golang 實現 appium/WebDriverAgent 的客戶端庫GolangAPPWeb客戶端
- Jmeter的客戶端實現與Keep-AliveJMeter客戶端Keep-Alive
- RetrofitJs – TypeScript實現的宣告式HTTP客戶端JSTypeScriptHTTP客戶端
- 藍芽客戶端和伺服器的實現藍芽客戶端伺服器
- 利用tirpc庫實現簡單的客戶端和服務端RPC客戶端服務端
- Golang 實現 Redis(6): 實現 pipeline 模式的 redis 客戶端GolangRedis模式客戶端
- Redis 設計與實現 (四)--事件、客戶端Redis事件客戶端
- Java建立WebService服務及客戶端實現JavaWeb客戶端
- C#實現組播源及客戶端C#客戶端
- 使用Oracle客戶端wallet實現匿名登入Oracle客戶端
- Redis的釋出訂閱及.NET客戶端實現Redis客戶端
- HTML轉PDF的純客戶端和純服務端實現方案HTML客戶端服務端
- SSLSocket實現服務端和客戶端雙向認證的例子服務端客戶端
- Qt實現網路聊天室(客戶端,服務端)QT客戶端服務端
- 實用的PostgreSQL客戶端:Postico for MacSQL客戶端Mac
- python 實現 TCP、UDP 客戶端最簡流程PythonTCPUDP客戶端
- redis客戶端實現高可用讀寫分離Redis客戶端
- 在 WPF 客戶端實現 AOP 和介面快取客戶端快取
- python實現douban.fm簡易客戶端Python客戶端
- Java建立WebService服務及客戶端實現(轉)JavaWeb客戶端