1. 程式人生 > >Android中Socket通訊的簡單實現

Android中Socket通訊的簡單實現

前言

Android Framework 層程式碼中大量使用了 Binder IPC 通訊方式,除此之外,Socket 也是一種重要的 IPC 通訊方式,比如StorageManagerService(8.0 之前叫 MountService)與 Vold 之前的通訊,SystemServer 和 Zygote 之間也是通過 Socket 進行通訊的。

本文簡單總結下 Android Java 層在使用 Socket 通訊時的一般步驟,然後給出一個簡單的 demo。

原理性的東西涉及到不同網路層之間的協議,本著簡單、實用、粗暴的原則,本文暫不涉及原理性的東西。


上圖是從 https://blog.csdn.net/yhaolpz/article/details/59483916 處扒來的圖片,以下例項程式碼也是從該處獲取,非原創。

1,Socket通訊的實現步驟

Socket 通訊和 Binder 通訊類似,也是一種 C/S 模型的通訊方式。

1.1 Server 服務端

步驟一: 建立一個伺服器 Socket

常見的一個伺服器 Socket 類是 ServerSocket,ServerSocket 類常用三個方法:binder 、accept、close。

bind 方法為 ServerSocket 繫結 IP 地址和埠號,並開始監聽該埠;accept 方法為 ServerSocket 接收請求並返回一個Socket 物件,accept 方法呼叫之後將一直阻塞直到有請求達到;close 方法關閉一個 ServerSocket 物件。

初始化是一般需要設定 IP 地址和埠號

步驟二: 通過監聽獲取一個用於通訊的 Socket 物件

這一步直接通過上述 accept 方法的執行就可實現

步驟三: 在一個新執行緒中,通過對 Socket 物件進行封裝,分別得到輸入、輸出流的引用物件,通過這兩個物件向 Client 端傳送或者從 Client 端接收資料,進而實現 Socket 通訊。

一般選擇在迴圈中讀取 Client 傳送過來的資訊,並作出對應的處理,比如反饋 Client 端:自己已成功收到相應的訊息。

步驟四: 在適當的時機關閉 Socket 連線

服務端程式碼:

public class SocketTest {

    private static final int PORT = 9999;
    private List<Socket> mList = new ArrayList<Socket>();
    private ServerSocket server = null;
    private ExecutorService mExecutorService = null;
    private String receiveMsg;
    private String sendMsg;

    public static void main(String[] args) {
        new SocketTest();
    }

    public SocketTest() {
        try {
            server = new ServerSocket(PORT);                         //步驟一
mExecutorService = Executors.newCachedThreadPool(); System.out.println("伺服器已啟動..."); Socket client = null; while (true) { client = server.accept(); //步驟二,每接受到一個新Socket連線請求,就會新建一個Thread去處理與其之間的通訊 mList.add(client); mExecutorService.execute(new Service(client)); } } catch (Exception e) { e.printStackTrace(); } } class Service implements Runnable { private Socket socket; private BufferedReader in = null; private PrintWriter printWriter=null; public Service(Socket socket) { //這段程式碼對應步驟三 this.socket = socket; try { printWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter( socket.getOutputStream(), "UTF-8")), true); in = new BufferedReader(new InputStreamReader( socket.getInputStream(),"UTF-8")); printWriter.println("成功連線伺服器"+"(伺服器傳送)"); System.out.println("成功連線伺服器"); } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { try { while (true) { //迴圈接收、讀取 Client 端傳送過來的資訊 if ((receiveMsg = in.readLine())!=null) { System.out.println("receiveMsg:"+receiveMsg); if (receiveMsg.equals("0")) { System.out.println("客戶端請求斷開連線"); printWriter.println("服務端斷開連線"+"(伺服器傳送)"); mList.remove(socket); in.close(); socket.close(); //接受 Client 端的斷開連線請求,並關閉 Socket 連線 break; } else { sendMsg = "我已接收:" + receiveMsg + "(伺服器傳送)"; printWriter.println(sendMsg); //向 Client 端反饋、傳送資訊 } } } } catch (Exception e) { e.printStackTrace(); } } } }

1.2 Client 客戶端

步驟一: 初始化 Socket 物件

客戶端一般選擇在一個新的執行緒中,初始化一個 Socket 物件,初始化是需要設定 IP 和埠號,以幫助低層網路路由找到相應的服務端程序。

步驟二: 獲取與 Server 端通訊的引用

此步和 Server 端建立連線後的步驟類似:根據步驟一中獲取的 Socket 物件,進行封裝,得到相應的輸入、輸出流物件,這些輸入、輸出流物件就是和 Server 端進行通訊的引用。

步驟三: 通過步驟二中得到的引用,迴圈的讀取(在新執行緒中) Server 端傳送過來的訊息,並做相應的處理

步驟四:在合適的時機關閉與 Server 端的 Socket 連線

參考以下客戶端程式碼

public class SocketActivity extends AppCompatActivity {

    private EditText mEditText;
    private TextView mTextView;
    private static final String TAG = "TAG";
    private static final String HOST = "192.168.23.1";
    private static final int PORT = 9999;
    private PrintWriter printWriter;
    private BufferedReader in;
    private ExecutorService mExecutorService = null;
    private String receiveMsg;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_socket);
        mEditText = (EditText) findViewById(R.id.editText);
        mTextView = (TextView) findViewById(R.id.textView);
        mExecutorService = Executors.newCachedThreadPool();
    }

    public void connect(View view) {
        mExecutorService.execute(new connectService());  //在一個新的執行緒中請求 Socket 連線
    }

    public void send(View view) {
        String sendMsg = mEditText.getText().toString();
        mExecutorService.execute(new sendService(sendMsg));
    }

    public void disconnect(View view) {
        mExecutorService.execute(new sendService("0"));
    }

    private class sendService implements Runnable {
        private String msg;

        sendService(String msg) {
            this.msg = msg;
        }

        @Override
        public void run() {
            printWriter.println(this.msg);
        }
    }

    private class connectService implements Runnable {
        @Override
        public void run() {//可以考慮在此處新增一個while迴圈,結合下面的catch語句,實現Socket物件獲取失敗後的超時重連,直到成功建立Socket連線
            try {
                Socket socket = new Socket(HOST, PORT);      //步驟一
                socket.setSoTimeout(60000);
                printWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(   //步驟二
                        socket.getOutputStream(), "UTF-8")), true);
                in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
                receiveMsg();
            } catch (Exception e) {
                Log.e(TAG, ("connectService:" + e.getMessage()));   //如果Socket物件獲取失敗,即連線建立失敗,會走到這段邏輯
            }
        }
    }

    private void receiveMsg() {
        try {
            while (true) {                                      //步驟三
                if ((receiveMsg = in.readLine()) != null) {
                    Log.d(TAG, "receiveMsg:" + receiveMsg);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            mTextView.setText(receiveMsg + "\n\n" + mTextView.getText());
                        }
                    });
                }
            }
        } catch (IOException e) {
            Log.e(TAG, "receiveMsg: ");
            e.printStackTrace();
        }
    }
}

2. 總結

原諒我這篇文章結構上的簡潔和草率,哈哈,第二部分就直接結束了可憐

在實現Socket通訊時要重點關注新執行緒while迴圈的使用。

在Android主執行緒中不能進行網路通訊的大原則下,Server端和Client端分別使用不同的機制,在新執行緒中啟動Socket連線;連線建立之後,通過while迴圈實現通訊雙方的“準實時”訊息處理。

相關推薦

AndroidSocket通訊簡單實現

前言Android Framework 層程式碼中大量使用了 Binder IPC 通訊方式,除此之外,Socket 也是一種重要的 IPC 通訊方式,比如StorageManagerService(8.0 之前叫 MountService)與 Vold 之前的通訊,Syst

AndroidMQTT的簡單實現(只是連線到伺服器,未實現傳送、接受資訊)

1.新增mqtt包到gradle.build a.在project的gradle.build中新增地址(P:我下載的參考例子是不用新增的,但是我自己寫的時候不新增就編譯不過去) allprojects { repositories { google()

AndroidHttps通訊實現_ 單向認證

客戶端與服務端單向認證即是在客戶端的網路請求和webview中設定信任所有證書,然後在與服務端進行Https網路通訊的時候,客戶端不必進行證書校驗也能進行網路通訊,否則就會報證書不受信異常。 缺陷:容易受到中間人攻擊。 概覽 TrustManager和Hos

AndroidHttps通訊實現_瞭解Https

概覽 什麼是Https Https和Http的區別 Https證書 什麼是Https HTTPS(全稱:Hypertext Transfer Protocol over Secure Socket Layer),是以安全為目標的HTTP通道,簡單講是

Android通過ListView的實現簡單新聞列表

Android中實現簡單的新聞列表 “本文主要針對Android新手,大神請繞道…” 使用到的第三方庫 Retrofit2+RxJava2 進行網路請和json資料的解析,註解框架:Butterknife 8.5.1 如果以上的框架還有同學不知道怎麼使用可以看看

AndroidHttps通訊實現_中間人攻擊、DNS欺騙和會話劫持

上一篇文章記述了在Android中使用Https進行單向認證的配置,但單向認證存在中嚴重的安全漏洞,其中最容易受到中間人攻擊和DNS欺騙以及會話劫持,本文主要講述進行中間人攻擊、DNS欺騙和會話劫持的方式。 概覽 什麼是中間人攻擊 模擬中間人攻擊

C#Socket通訊程式設計的非同步實現

本文將在C#中Socket同步通訊的基礎上,分析和研究Socket非同步程式設計的實現方法,目的是深入瞭解Socket程式設計的基本原理,增強對網路遊戲開發相關內容的認識。 什麼是Socket程式設計的非同步是實現 所謂Socket程式設計的非同步實現是指按

androidping命令的實現

ack ces buffered amr 實現 int time() ade article /** * 推斷Ping 網址是否返回成功 * * @param netAddress * @return */ public static String isPingSuc

AndroidSocket大文件斷點上傳

lai 大於 兩個類 bundle use 分配 1.0 應該 subst 什麽是Socket? 所謂Socket通常也稱作“套接字”,用於描述IP地址和端口,是一個通信連的句柄,應用程序通常通過“套接字&rdquo

AndroidAlertDialog的簡單使用

android中彈框很多種,alert框,dialog,AlertDialog,popupwindow,DialogFragment,toast,dialog樣式的activity等等,今天講解AlertDialog的簡單使用。 1 AlertDialog.Builder 設定相關引

android定時器的實現學習

資料來自於 簡書 沿路旅程如歌蛻變 點這裡 利用handler.postDelay()方法來實現定時器計時 下面的程式碼實現了6s倒計時,計時後,自動停止計時並移除runnable. public class MainActivity extends AppCompat

AndroidListView的簡單使用

動態新增單行列表: 首先前提是你的佈局檔案裡有一個ListView 單行列表的新增只需要一個list集合即可,使用ArrayAdapter陣列介面卡繫結更新就行了 首先宣告一個ArrayAdapter物件: ArrayAdapter adapter adapter = new ArrayAdapter(

通過aspectj對Android資料統計的簡單實現

功能需求 一個專案實現之後,我們並不知道使用者對某個部分的使用頻率是對少,為了更好的來對專案各個功能的使用統計,我們需要做一些資料埋點的功能,也就是每當使用者點選按鈕的時候,都對這次點選進行儲存處理,然後再之後統一上傳到伺服器,進行資料分析。 實現思路 條件 假如,當前有

一文了解Android路由(Router)的實現

Router 對於一個功能越來越複雜的APP來說,路由對於程式碼的解耦、頁面靈活跳轉配置、頁面攔截功能提供了很好的支援。下面我將分析業界比較出名的兩個路由框架WMRouter和ARouter的原始碼,瞭解他們的實現原理。 這兩個框架的實現核心原理是差不多的: 通過註解標註路由資訊,在編譯期動態掃描路由資訊

AndroidSocket通訊

Android裡面使用Socket與伺服器之間進行通訊: 首先建立一個SocThread類 package com.junto.sockettest; import android.content.Context; import android.content.SharedPref

android如何使用GPU實現硬體加速,3D渲染

已開通新的部落格,後續文字都會發到新部落格 http://www.0xfree.top --- 首先來看一些名詞解釋     GPU:Graphic  Processing Unit (圖形處理器)&nb

android 呼叫手機打電話 簡單實現

首先看下佈局xml ,我的事一個button按鈕 點選 打電話 ,手機號是自己定義,這個你可以根據自己邏輯寫 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas

Android轉盤抽獎的簡單實現

public class ZhuanPan2 extends View implements View.OnClickListener{ private Paint mPaint; private int mwidth; private int mpidding; p

Android使用JiaoZiVideoPlayer來實現視訊列表播放的效果

目的:我這邊是想做類似於鬥魚直播裡的視訊模組的視訊列表播放形式。 然後下載程式碼,根據自己需要的樣式去找相應的程式碼進行研究。 效果圖如下: 使用步驟: (1)新增遠端依賴: /*呼叫Video視訊播放器*/ implementation 'cn.jzvd:

關於JavaSocket通訊時使用ObjectInputStream與ObjectOutputStream的順序問題

在Java中使用Socket與ServerSocket建立客戶機和伺服器時,若採用ObjectInputStream與ObjectOutputStream建立通訊,則需要注意兩個流的順序。否則會發生兩方互相等待導致死鎖。 下面通過一個例子來證明: 伺服器: package com.gar