1. 程式人生 > >基於Socket的TCP長連線(服務端Java+客戶端Android),Service配合AIDL實現

基於Socket的TCP長連線(服務端Java+客戶端Android),Service配合AIDL實現

最近公司的專案要求加入訊息推送功能,由於專案使用者量不是很大,推送需求不是很嚴格,而且是基於內網的推送,所以我捨棄了使用三方的推送服務,自己使用Socket寫了推送功能,剪出一個小Demo來跟大家分享一下,有不足之處希望讀者能夠多多給出建議。
關於Socket的TCP和UDP協議,相信大家都是很清楚的,當然做長連線兩者都是可以的,據說QQ和微信360等使用的UDP做的,使用兩個Service相互監控保持不被系統殺死,但是我目前做不了他們那樣的效果,如果各位有更好的辦法,可以共享一下,我們言歸正傳。
程式碼還是相當粗糙的,目的是練習使用Socket。伺服器端使用一個執行緒的集合儲存不同的客戶端,相關程式碼如下:

public class ServerDemo {

	private int count = 0;

	private boolean isStartServer = false;

	private ArrayList<SocketThread> mThreadList = new ArrayList<SocketThread>();



	public static void main(String[] args) throws IOException {



		ServerDemo server = new ServerDemo();

		server.start();

	}



	/**

	 * 開啟服務端的Socket

	 * @throws IOException

	 */

	public void start() throws IOException {

		// 啟動服務ServerSocket,設定埠號

		ServerSocket ss = new ServerSocket(9001);

		System.out.println("服務端已開啟,等待客戶端連線:");

		isStartServer = true;

		int socketID = 0;

		Socket socket = null;

		startMessageThread();

		while (isStartServer) {

			// 此處是一個阻塞方法,當有客戶端連線時,就會呼叫此方法

			socket = ss.accept();

			System.out.println("客戶端連線成功" + socket.getInetAddress());

			// 4. 為這個客戶端的Socket資料連線

			SocketThread thread = new SocketThread(socket, socketID++);

			thread.start();

			mThreadList.add(thread);

		}

	}



	private void startMessageThread() {

		new Timer().schedule(new TimerTask() {



			@Override

			public void run() {

				try {

					for (SocketThread st : mThreadList) {// 分別向每個客戶端傳送訊息

						if (st.socket == null || st.socket.isClosed())

							continue;

						System.out.println("客戶端的userId:" + st.userId + "  訊息編號:" + count);

						if (st.userId == null || "".equals(st.userId))// 如果暫時沒有確定Socket對應的使用者Id先不發

							continue;

						String content = "我是從伺服器發來的訊息:" + count;

						

						// 根據userId模擬服務端向不同的客戶端推送訊息

						if (count % 2 == 0) {

							if (st.userId.equals("002"))

								content = "我是從伺服器發發送給使用者002的訊息:" + count;

							else

								continue;

						} else {

							if (st.userId.equals("001"))

								content = "我是從伺服器發發送給使用者001的訊息:" + count;

							else

								continue;

						}

						SocketMessage message = new SocketMessage();

						message.setFrom(Custom.NAME_SERVER);

						message.setTo(Custom.NAME_CLIENT);

						message.setMessage(content);

						message.setType(Custom.MESSAGE_EVENT);

						message.setUserId(st.userId);

						BufferedWriter writer = st.writer;

						String jMessage = Util.initJsonObject(message).toString() + "\n";

						writer.write(jMessage);

						writer.flush();

						System.out.println("向客戶端" + st.socket.getInetAddress() + "傳送了訊息:" + content);

					}

					count++;

				} catch (IOException e) {

					// TODO Auto-generated catch block

					e.printStackTrace();

				}



			}

		}, 0, 1000 * 30);//此處設定定時器目的是模仿服務端向客戶端推送訊息,假定每隔30秒推送一條訊息



	}



	/**

	 * 關閉與SocketThread所代表的客戶端的連線

	 * @param socketThread要關閉的客戶端

	 * @throws IOException

	 */

	private void closeSocketClient(SocketThread socketThread) throws IOException {

		if (socketThread.socket != null && !socketThread.socket.isClosed()) {

			if (socketThread.reader != null)

				socketThread.reader.close();

			if (socketThread.writer != null)

				socketThread.writer.close();

			socketThread.socket.close();

		}

		mThreadList.remove(socketThread);

		socketThread = null;

	}



	/**

	 * 客戶端Socket執行緒,

	 * @author 華碩

	 *

	 */

	public class SocketThread extends Thread {



		public int socketID;

		public Socket socket;//客戶端的Socket

		public BufferedWriter writer;

		public BufferedReader reader;

		public String userId;//客戶端的UserId

		private long lastTime;



		public SocketThread(Socket socket, int count) {

			socketID = count;

			this.socket = socket;

			lastTime = System.currentTimeMillis();

		}



		@Override

		public void run() {

			super.run();



			try {

				reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

				writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

				//迴圈監控讀取客戶端發來的訊息

				while (isStartServer) {

					// 超出了傳送心跳包規定時間,說明客戶端已經斷開連線了這時候要斷開與該客戶端的連線

					long interval = System.currentTimeMillis() - lastTime;

					if (interval >= (Custom.SOCKET_ACTIVE_TIME * 1000 * 4)) {

						System.out.println("客戶端發包間隔時間嚴重延遲,可能已經斷開了interval:" + interval);

						System.out.println("Custom.SOCKET_ACTIVE_TIME * 1000:" + Custom.SOCKET_ACTIVE_TIME * 1000);

						closeSocketClient(this);

						break;

					}

					if (reader.ready()) {

						lastTime = System.currentTimeMillis();

						System.out.println("收到訊息,準備解析:");

						String data = reader.readLine();

						System.out.println("解析成功:" + data);

						SocketMessage from = Util.parseJson(data);

						//給UserID賦值,此處是我們專案的需求,根據客戶端不同的UserId來分別進行推送

						if (userId == null || "".equals(userId))

							userId = from.getUserId();

						SocketMessage to = new SocketMessage();

						if (from.getType() == Custom.MESSAGE_ACTIVE) {//心跳包

							System.out.println("收到心跳包:" + socket.getInetAddress());

							to.setType(Custom.MESSAGE_ACTIVE);

							to.setFrom(Custom.NAME_SERVER);

							to.setTo(Custom.NAME_CLIENT);

							to.setMessage("");

							to.setUserId(userId);

							writer.write(Util.initJsonObject(to).toString() + "\n");

							writer.flush();

						} else if (from.getType() == Custom.MESSAGE_CLOSE) {//關閉包

							System.out.println("收到斷開連線的包:" + socket.getInetAddress());

							to.setType(Custom.MESSAGE_CLOSE);

							to.setFrom(Custom.NAME_SERVER);

							to.setTo(Custom.NAME_CLIENT);

							to.setMessage("");

							to.setUserId(userId);

							writer.write(Util.initJsonObject(to).toString() + "\n");

							writer.flush();

							closeSocketClient(this);

							break;

						} else if (from.getType() == Custom.MESSAGE_EVENT) {//事件包,客戶端可以向服務端傳送自定義訊息

							System.out.println("收到普通訊息包:" + from.getMessage());

						}

					}

					Thread.sleep(100);

				}



			} catch (Exception e) {

				e.printStackTrace();

			}



		}

	}

}

當服務端收到客戶端的連線時候,就開啟執行緒用來接收客戶端的訊息(心跳包的訊息或者是普通的訊息),伺服器端模擬訊息推送,利用定時器每隔一段時間就像客戶端推送一條訊息。我的訊息分為三種:
心跳訊息,客戶端每隔一段時間就會向伺服器傳送一條心跳訊息,服務端收到之後會馬上返回一條心跳訊息給客戶端,以此來保持連線。
普通訊息,客戶端與服務端的資料互動。
斷開連線訊息,當服務端收到客戶端的斷開連線訊息時,會立馬給客戶端返回斷開連線訊息,同時服務端會主動與客戶端斷開連線,並從執行緒任務列表把該客戶端Socket移除,只有再次連線才會被新增進來。客戶端收到服務端的斷開回執,也會斷開連線,防止資源浪費和異常發生。
因為我專業是做Android開發的,重點說一下客戶端的程式碼:

使用Service的持久存活來保持Socket不被意外斷開

在onStartCommand方法返回START_STICKY,如果Service由於記憶體不夠被意外殺死,那麼等記憶體夠了之後,還會重啟

 @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG, "onStartCommand(Intent intent, int flags, int startId)");
//        return super.onStartCommand(intent, flags, startId);
        //當Service重啟時候,判斷一下,如果Socket斷開了連線,但是儲存的狀態還是連線狀態,那就是意外的斷開,需要重連
        if (isServerClose() && SocketServiceSP.getInstance(SocketService.this).isSocketConnect())
            connectSocket();
        return START_STICKY;//設定START_STICKY為了使服務被意外殺死後可以重啟
    }

註冊廣播,當Service走onDestroy()方法時候,傳送廣播,重啟服務

 @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "onCreate()");
        SocketServiceSP.getInstance(this).saveSocketServiceStatus(true);//儲存了Service的開啟狀態
        //收到Service被殺死的廣播,立即重啟
        restartBR = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                Log.e(TAG, "SocketServer重啟了......");
                String action = intent.getAction();
                if (!TextUtils.isEmpty(action) && action.equals("socketService_killed")) ;
                Intent sIntent = new Intent(SocketService.this, SocketService.class);
                startService(sIntent);
                SocketServiceSP.getInstance(SocketService.this).saveSocketServiceStatus(true);//儲存了Service的開啟狀態
                //當Service重啟時候,判斷一下,如果Socket斷開了連線,但是儲存的狀態還是連線狀態,那就是意外的斷開,需要重連
                if (isServerClose() && SocketServiceSP.getInstance(SocketService.this).isSocketConnect())
                    connectSocket();
            }
        };
        registerReceiver(restartBR, new IntentFilter("socketService_killed"));
    }
/**
     * 銷燬Service同時要銷燬Socket
     */
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy()");
        if (mReadThread != null)
            mReadThread.release();
        releaseLastSocket(mSocket);
        sendBroadcast(new Intent("socketService_killed"));
        SocketServiceSP.getInstance(SocketService.this).saveSocketServiceStatus(false);
        unregisterReceiver(restartBR);
    }

Service的啟動使用的startService方法啟動的,為了使使用者能夠操作介面來連線和斷開Socket,就需要Service程序與Activity程序進行互動,而這裡需要用到AIDL技術,AIDL介面的方法引數使用了自定義的SocketMessage類,所以還需要實現Parcelable介面。
關於AIDL的使用,就不進行詳細的介紹了,有不清楚的朋友可以私下交流
下面看一下整個Service的程式碼

package com.herenit.socketpushdemo.core;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.BitmapFactory;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.support.v7.app.NotificationCompat;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import com.herenit.socketpushdemo.ISocketMessageListener;
import com.herenit.socketpushdemo.ISocketServiceInterface;
import com.herenit.socketpushdemo.MainActivity;
import com.herenit.socketpushdemo.R;
import com.herenit.socketpushdemo.bean.SocketMessage;
import com.herenit.socketpushdemo.common.Custom;
import com.herenit.socketpushdemo.common.SocketServiceSP;
import com.herenit.socketpushdemo.common.Util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.lang.ref.WeakReference;
import java.net.Socket;

/**
 * Created by HouBin on 2017/3/14.
 * 與伺服器保持長連線的Service
 */

public class SocketService extends Service {
    private final String TAG = SocketService.class.getSimpleName();
    //Service例項,用於在Activity中進行連線斷開發訊息等圖形介面化的操作

    //Socket的弱引用
    private WeakReference<Socket> mSocket;

    //訊息發出的時間(不管是心跳包還是普通訊息,傳送完就會跟新時間)
    private long sendTime = 0;

    private final int MSG_WHAT_CONNECT = 111; //連線Socket
    private final int MSG_WHAT_DISCONNECT = 112;//斷開Socket
    private final int MSG_WHAT_SENDMESSAGE = 113;//傳送訊息

    /**
     * 處理Socket的連線斷開發訊息的Handler機制
     */
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_WHAT_CONNECT:
                    if (isServerClose()) {
                        connectSocket();
                    } else {
                        Toast.makeText(SocketService.this, "Socket已經連線上了", Toast.LENGTH_SHORT).show();
                    }
                    break;
                case MSG_WHAT_DISCONNECT:
                    if (isServerClose())
                        Toast.makeText(SocketService.this, "Socket已經斷開了", Toast.LENGTH_SHORT).show();
                    else
                        interruptSocket();
                    break;
                case MSG_WHAT_SENDMESSAGE:
                    if (isServerClose()) {
                        Toast.makeText(SocketService.this, "請先連線Socket", Toast.LENGTH_SHORT).show();
                    } else {
                        SocketMessage socketMessage = (SocketMessage) msg.obj;
                        try {
                            SocketService.this.sendMessage(socketMessage);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
            }
        }
    };

    //讀取伺服器端發來的訊息的執行緒
    private ReadThread mReadThread;

    //監控服務被殺死重啟的廣播,保持服務不被殺死
    private BroadcastReceiver restartBR;

    public SocketService() {
        super();
    }

    /**
     * 建立Service的同時要建立Socket
     */
    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "onCreate()");
        SocketServiceSP.getInstance(this).saveSocketServiceStatus(true);//儲存了Service的開啟狀態
        //收到Service被殺死的廣播,立即重啟
        restartBR = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                Log.e(TAG, "SocketServer重啟了......");
                String action = intent.getAction();
                if (!TextUtils.isEmpty(action) && action.equals("socketService_killed")) ;
                Intent sIntent = new Intent(SocketService.this, SocketService.class);
                startService(sIntent);
                SocketServiceSP.getInstance(SocketService.this).saveSocketServiceStatus(true);//儲存了Service的開啟狀態
                //當Service重啟時候,判斷一下,如果Socket斷開了連線,但是儲存的狀態還是連線狀態,那就是意外的斷開,需要重連
                if (isServerClose() && SocketServiceSP.getInstance(SocketService.this).isSocketConnect())
                    connectSocket();
            }
        };
        registerReceiver(restartBR, new IntentFilter("socketService_killed"));
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG, "onStartCommand(Intent intent, int flags, int startId)");
//        return super.onStartCommand(intent, flags, startId);
        //當Service重啟時候,判斷一下,如果Socket斷開了連線,但是儲存的狀態還是連線狀態,那就是意外的斷開,需要重連
        if (isServerClose() && SocketServiceSP.getInstance(SocketService.this).isSocketConnect())
            connectSocket();
        return START_STICKY;//設定START_STICKY為了使服務被意外殺死後可以重啟
    }


    /**
     * 客戶端通過Socket與服務端建立連線
     */
    public void connectSocket() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Socket socket = new Socket(Custom.SERVER_HOST, Custom.SERVER_PORT);
                    //這裡儲存Socket當前已經連線上了
                    SocketServiceSP.getInstance(SocketService.this).saveSocketConnectStatus(true);
                    socket.setSoTimeout(Custom.SOCKET_CONNECT_TIMEOUT * 1000);
                    Log.e(TAG, "Socket連線成功。。。。。。");
                    mSocket = new WeakReference<Socket>(socket);
                    mReadThread = new ReadThread(socket);
                    mReadThread.start();
                    mHandler.postDelayed(activeRunnable, Custom.SOCKET_ACTIVE_TIME * 1000);//開啟定時器,定時傳送心跳包,保持長連線
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    /**
     * 傳送心跳包的任務
     */
    private Runnable activeRunnable = new Runnable() {
        @Override
        public void run() {
            if (System.currentTimeMillis() - sendTime >= Custom.SOCKET_ACTIVE_TIME * 1000) {
                SocketMessage message = new SocketMessage();
                message.setType(Custom.MESSAGE_ACTIVE);
                message.setMessage("");
                message.setFrom(Custom.NAME_CLIENT);
                message.setTo(Custom.NAME_SERVER);
                try {
                    if (!sendMessage(message)) {
                        if (mReadThread != null)
                            mReadThread.release();
                        releaseLastSocket(mSocket);
                        connectSocket();
                    }
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            mHandler.postDelayed(this, Custom.SOCKET_ACTIVE_TIME * 1000);
        }
    };

    /**
     * 傳送訊息到服務端
     *
     * @param message
     * @return
     */
    public boolean sendMessage(SocketMessage message) throws RemoteException {
        message.setUserId("001");
        if (mSocket == null || mSocket.get() == null) {
            return false;
        }
        Socket socket = mSocket.get();
        try {
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            if (!socket.isClosed()) {
                String jMessage = Util.initJsonObject(message).toString() + "\n";
                writer.write(jMessage);
                writer.flush();
                Log.e(TAG, "傳送訊息:" + jMessage);
                sendTime = System.currentTimeMillis();//每次傳送成資料,就改一下最後成功傳送的時間,節省心跳間隔時間 
                if (message.getType() == Custom.MESSAGE_EVENT) {//通知實現了訊息監聽器的介面,讓其跟新訊息列表
                    messageListener.updateMessageList(message);
                }
            } else {
                return false;
            }
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 讀取訊息的執行緒
     */
    class ReadThread extends Thread {
        private WeakReference<Socket> mReadSocket;
        private boolean isStart = true;

        public ReadThread(Socket socket) {
            mReadSocket = new WeakReference<Socket>(socket);
        }

        public void release() {
            isStart = false;
            releaseLastSocket(mReadSocket);
        }

        @Override
        public void run() {
            super.run();
            Socket socket = mReadSocket.get();
            if (socket != null && !socket.isClosed()) {
                try {
                    BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    while (isStart) {
                        if (reader.ready()) {
                            String message = reader.readLine();
                            Log.e(TAG, "收到訊息:" + message);
                            SocketMessage sMessage = Util.parseJson(message);
                            if (sMessage.getType() == Custom.MESSAGE_ACTIVE) {//處理心跳回執

                            } else if (sMessage.getType() == Custom.MESSAGE_EVENT) {//事件訊息
                                if (messageListener != null)
                                    messageListener.updateMessageList(sMessage);
                                sendNotification(sMessage);
                            } else if (sMessage.getType() == Custom.MESSAGE_CLOSE) {//斷開連線訊息回執
                                mHandler.removeCallbacks(activeRunnable);
                                release();
                                releaseLastSocket(mSocket);
                            }
                        }
                        Thread.sleep(100);//每隔0.1秒讀取一次,節省點資源
                    }
                } catch (IOException e) {
                    release();
                    releaseLastSocket(mSocket);
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    //通知的ID,為了分開顯示,需要根據Id區分
    private int nId = 0;

    /**
     * 收到時間訊息,傳送通知提醒
     *
     * @param sMessage
     */
    private void sendNotification(SocketMessage sMessage) {
        //為了版本相容,使用v7包的BUILDER
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
        //狀態列顯示的提示,有的手機不顯示
        builder.setTicker("簡單的Notification");
        //通知欄標題
        builder.setContentTitle("from" + sMessage.getFrom() + "的訊息");
        //通知欄內容
        builder.setContentText(sMessage.getMessage());
        //通知內容摘要
        builder.setSubText(sMessage.getUserId());
        //在通知右側的時間下面用來展示一些其他資訊
//        builder.setContentInfo("其他");
        //用來顯示同種通知的數量,如果設定了ContentInfo屬性,則NUmber屬性會被覆蓋,因為二者顯示的位置相同
//        builder.setNumber(3);
        //可以點選通知欄的刪除按鈕
        builder.setAutoCancel(true);
        //系統狀態列顯示的小圖示
        builder.setSmallIcon(R.mipmap.jpush_notification_icon);
        //通知下拉顯示的大圖示
        builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
        //點選通知跳轉的INTENT
        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 1, intent, 0);
        builder.setContentIntent(pendingIntent);//點選跳轉
        //通知預設的聲音,震動,呼吸燈
        builder.setDefaults(NotificationCompat.DEFAULT_ALL);
        Notification notification = builder.build();
        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        manager.notify(nId, notification);
        nId++;
    }

    /**
     * 釋放Socket,並關閉
     *
     * @param socket
     */
    private void releaseLastSocket(WeakReference<Socket> socket) {
        //正常的斷開連線,這裡儲存斷開連線的狀態
        SocketServiceSP.getInstance(this).saveSocketConnectStatus(false);
        if (socket != null) {
            Socket so = socket.get();
            try {
                if (so != null && !so.isClosed())
                    so.close();
                socket.clear();
                Log.e(TAG, "Socket斷開連線。。。。。。");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 判斷是否斷開連線,斷開返回true,沒有返回false
     *
     * @return
     */
    public boolean isServerClose() {
        try {
            if (mSocket != null && mSocket.get() != null) {
                mSocket.get().sendUrgentData(0);//傳送1個位元組的緊急資料,預設情況下,伺服器端沒有開啟緊急資料處理,不影響正常通訊
                return false;
            }
        } catch (Exception se) {
            return true;
        }
        return true;
    }

    /**
     * 銷燬Service同時要銷燬Socket
     */
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy()");
        if (mReadThread != null)
            mReadThread.release();
        releaseLastSocket(mSocket);
        sendBroadcast(new Intent("socketService_killed"));
        SocketServiceSP.getInstance(SocketService.this).saveSocketServiceStatus(false);
        unregisterReceiver(restartBR);
    }

    /**
     * 對外提供的斷開Socket連線的方法(向伺服器傳送斷開的包,伺服器收到後會與之斷開)
     */
    public void interruptSocket() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                SocketMessage message = new SocketMessage();
                message.setType(Custom.MESSAGE_CLOSE);
                message.setMessage("");
                message.setFrom(Custom.NAME_CLIENT);
                message.setTo(Custom.NAME_SERVER);
                try {
                    sendMessage(message);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.e(TAG, "onUnbind(Intent intent)");
        return super.onUnbind(intent);
    }

    @Override
    public void onRebind(Intent intent) {
        Log.e(TAG, "onBind(Intent intent)");
        super.onRebind(intent);
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "onRebind(Intent intent) ");
        return mBinder;
    }

    /**************************************************
     * AIDL
     ********************************************************/

    private ISocketMessageListener messageListener;
    private Binder mBinder = new ISocketServiceInterface.Stub() {
        private static final String ITAG = "ISocketServiceInterface";

        /**
         * 客戶端要求連線Socket
         * @throws RemoteException
         */
        @Override
        public void connectSocket() throws RemoteException {
            Log.e(ITAG, "connectSocket");
            mHandler.sendEmptyMessage(MSG_WHAT_CONNECT);
        }

        /**
         * 客戶端要求斷開Socket連線
         * @throws RemoteException
         */
        @Override
        public void disConnectSocket() throws RemoteException {
            Log.e(ITAG, "disConnectSocket");
            mHandler.sendEmptyMessage(MSG_WHAT_DISCONNECT);
        }

        /**
         * 客戶端向伺服器端傳送訊息
         * @param message
         * @throws RemoteException
         */
        @Override
        public void sendMessage(SocketMessage message) throws RemoteException {
            Log.e(ITAG, "sendMessage");
            Message msg = Message.obtain();
            msg.what = MSG_WHAT_SENDMESSAGE;
            msg.obj = message;
            mHandler.sendMessage(msg);
        }

        /**
         * 客戶端新增訊息監聽器,監聽伺服器端發來的訊息
         * @param listener
         * @throws RemoteException
         */
        @Override
        public void addMessageListener(ISocketMessageListener listener) throws RemoteException {
            Log.e(ITAG, "addMessageListener");
            messageListener = listener;
        }

        @Override
        public void removeMessageListener(ISocketMessageListener listener) throws RemoteException {
            Log.e(ITAG, "removeMessageListener");
            messageListener = null;
        }
    };
}

程式碼的註釋還是比較詳細的,整體的程式碼大家可以去我的GitHub上下載
服務端程式碼
客戶端程式碼
時間比較緊,介紹的不是很詳細,很抱歉,大家有疑問就直接看整個專案或者直接聯絡我吧!