同一局域網內的兩個apk通過socket互信通訊

前言:

最近客戶提出了一個這樣的需求,他們的apk想要獲取到我們rk3188板的參數和一些控制板卡的命令如(音量+、音量-、關機、重啓、亮度+、亮度-)等等。但是又不想讓他們的apk直接和板卡有任務關係,所以就採用到了這樣的辦法,採用sokcet局域網通信機制。把客戶的apk作爲socket服務端,然後再寫一個apk作爲socket客戶端,裝在同一臺機器上面,這樣就可以實現客戶的需求了。


步驟一:創建一個ClientServer Demo 並 編寫客戶端代碼

代碼裏面都有詳細註釋,寫在服務裏面的。
由於博主是用的以太網所以HOST地址填寫的:127.0.0.1 PORT地址隨便填寫的。
如果你們用的wifi或者手機共享網絡,HOST地址就填寫相應的址

MainSocketClientService.java


package com.android.clientserver;

import android.app.Service;
import android.content.Intent;
import android.media.AudioManager;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by Administrator on 2018/5/19.
 */

public class MainSocketClientService extends Service {

    private static final String TAG = "MainSocketClientService";

    private static final String HOST = "127.0.0.1";
    private static final int PORT = 12345;
    private WeakReference<Socket> mSocket;
    private ReadThread mReadThread;

    private static SocketThread socketThread = null;

    private AudioManager mAudioManager;
    private double maxVolume;

    private synchronized SocketThread instance() {
        if (socketThread == null) {
            socketThread = new SocketThread();
        }
        return socketThread;
    }

    private synchronized void destroyInstance() {
        if (socketThread != null) {
            socketThread = null;
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "MainSocketClientService onCreate......");
        mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
        maxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
        instance().start();
    }

    public class SocketThread extends Thread {
        @Override
        public void run() {
            super.run();
            initSocket();
        }
    }

    /**
     * 初始化SocketReadThread
     */
    private void initSocket() {
        try {
            Socket socket = new Socket(HOST, PORT);
            socket.setOOBInline(true);
            mSocket = new WeakReference<Socket>(socket);
            mReadThread = new ReadThread(socket);
            mReadThread.start();
            // 每隔十秒發送一個心跳給服務端,判斷socket連接是否ok
            new Timer().schedule(new TimerTask() {
                @Override
                public void run() {
                    String heartBeat = "{\"cmd\":\"heartbeat\"}" + "#end#" + "\t\t" + new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date().getTime());
                    boolean isSuccess = sendMsg(heartBeat);
                    Log.d(TAG, "MainSocketClientService isSuccess = " + isSuccess);
                    // 如果isSuccess返回false,就說明socket連接掉線,然後重連
                    if (!isSuccess) {
                        Log.d(TAG, "MainSocketClientService socket斷開連接,重連socket......");
                        mReadThread.release();
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                initSocket();
                            }
                        }).start();
                    }
                }
            }, 0, 5000);
        } catch (IOException e) {
            e.printStackTrace();
            Log.d(TAG, "MainSocketClientService initSocket IOException e = " + e.getMessage());
            try {
                Thread.sleep(5000);
                initSocket();
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        }
    }

    /**
     * 接收來自服務器的數據
     */
    class ReadThread extends Thread {
        private WeakReference<Socket> mWeakSocket;
        private boolean isStart = true;

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

        public void release() {
            isStart = false;
            if (mWeakSocket != null) {
                releaseLastSocket(mWeakSocket);
            }
        }

        @Override
        public void run() {
            super.run();
            Socket socket = mWeakSocket.get();
            if (null != socket) {
                try {
                    InputStream is = socket.getInputStream();
                    byte[] buffer = new byte[1024 * 4];
                    int length = 0;
                    while (!socket.isClosed() && !socket.isInputShutdown() && isStart && ((length = is.read(buffer)) != -1)) {
                        Log.d(TAG, "MainSocketClientService ReadThread socket = " + socket + "\r\n" + "length = " + length);
                        if (length > 0) {
                            String getServerMessage = new String(Arrays.copyOf(buffer, length)).trim();
                            Log.d(TAG, "MainSocketClientService ReadThread getServerMessage = " + getServerMessage);
                            JSONObject jsonObject = new JSONObject(getServerMessage);
                            String cmd = jsonObject.getJSONObject("data").getString("cmd");
                            switch (cmd) {
                                case "increaseVoice":// 音量+ 100
                                    Log.d(TAG, "MainSocketClientService increaseVoice......");
                                    double increaseVolume = jsonObject.getJSONObject("data").getInt("increaseVolume");
                                    mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, (int) Math.floor(maxVolume * (increaseVolume / 100)), 0);
                                    break;
                                case "reduceVoice":// 音量- 0
                                    Log.d(TAG, "MainSocketClientService reduceVoice......");
                                    double reduceVolume = jsonObject.getJSONObject("data").getInt("reduceVolume");
                                    mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, (int) Math.floor(maxVolume * (reduceVolume / 100)), 0);
                                    break;
                                case "shutdown":// 關機
                                    Log.d(TAG, "MainSocketClientService shutdown......");
                                    int shutdownTime = jsonObject.getJSONObject("data").getInt("shutdownTime");
                                    String[] arrayShutDown = {"su", "-c", "reboot -p"};
                                    try {
                                        Thread.sleep(shutdownTime * 1000);
                                        Runtime.getRuntime().exec(arrayShutDown);
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                        Log.d(TAG, "MainSocketClientService shutdown IOException e = " + e.getMessage());
                                    } catch (InterruptedException e) {
                                        e.printStackTrace();
                                    }
                                    break;
                                case "reboot":// 重啓機器
                                    Log.d(TAG, "MainSocketClientService reboot......");
                                    int rebootTime = jsonObject.getJSONObject("data").getInt("rebootTime");
                                    String[] arrayReboot = {"su", "-c", "reboot"};
                                    try {
                                        Thread.sleep(rebootTime * 1000);
                                        Runtime.getRuntime().exec(arrayReboot);
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                        Log.d(TAG, "MainSocketClientService reboot IOException e = " + e.getMessage());
                                    } catch (InterruptedException e) {
                                        e.printStackTrace();
                                    }
                                    break;
                                case "increaseBrightness":// 亮度+ 100
                                    Log.d(TAG, "MainSocketClientService increaseBrightness......");
                                    double addBrightnessValue = jsonObject.getJSONObject("data").getInt("addBrightnessValue");
                                    break;
                                case "reduceBrightness":// 亮度- 0
                                    Log.d(TAG, "MainSocketClientService reduceBrightness......");
                                    double reduceBrightnessValue = jsonObject.getJSONObject("data").getInt("reduceBrightnessValue");
                                    break;
                                case "machineParameters":// 獲取到板卡參數發送到服務端app
                                    Log.d(TAG, "MainSocketClientService machineParameters......");
                                    String wifiMacAddress = DeviceUtils.getWlanMac();
                                    String versionName = DeviceUtils.getVersionName(MainSocketClientService.this);
                                    int versionCode = DeviceUtils.getVersionCode(MainSocketClientService.this);
                                    String appName = DeviceUtils.getAppName(MainSocketClientService.this);
                                    JSONObject jsonObject1 = new JSONObject();
                                    jsonObject1.put("wifiMacAddress", wifiMacAddress);
                                    jsonObject1.put("versionName", versionName);
                                    jsonObject1.put("versionCode", versionCode);
                                    jsonObject1.put("appName", appName);
                                    String machineParametersJsonData = jsonObject1.toString() + "#end#";
                                    Log.d(TAG, "MainSocketClientService machineParametersJsonData = " + machineParametersJsonData);
                                    sendMsg(machineParametersJsonData);
                                    break;
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    Log.d(TAG, "MainSocketClientService ReadThread IOException e = " + e.getMessage());
                } catch (JSONException e) {
                    e.printStackTrace();
                    Log.d(TAG, "MainSocketClientService ReadThread JSONException e = " + e.getMessage());
                }
            }
        }
    }

    /**
     * 從客戶端app通過socket傳輸數據到服務端app
     *
     * @param msg
     * @return
     */
    private boolean sendMsg(final String msg) {
        if (null == mSocket || null == mSocket.get()) {
            Log.d(TAG, "MainSocketClientService mSocket爲空或者mSocket.get()爲空......");
            return false;
        }
        final Socket soc = mSocket.get();
        if (!soc.isClosed() && !soc.isOutputShutdown()) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        OutputStream os = soc.getOutputStream();
                        String sendMessage = msg + "\r\n";
                        if (sendMessage != null && !"".equals(sendMessage)) {
                            os.write(sendMessage.getBytes());
                            os.flush();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                        Log.d(TAG, "MainSocketClientService sendMsg IOException e = " + e.getMessage());
                    }
                }
            }).start();
        } else {
            Log.d(TAG, "MainSocketClientService soc.isClosed並且soc.isOutputShutdown()......");
            return false;
        }
        return true;
    }

    private void releaseLastSocket(WeakReference<Socket> mSocket) {
//        try{
//            if(null != mSocket){
//                Socket sk = mSocket.get();
//                if(sk == null){
//                    return;
//                }
//                if(!sk.isClosed()){
//                    sk.close();
//                }
//                sk = null;
//                mSocket = null;
//            }
//        }catch (IOException e){
//            e.printStackTrace();
//            Log.d(TAG,"MainSocketClientService releaseLastSocket e= " + e.getMessage() );
//        }
        try {
            if (mSocket != null) {
                Socket sk = mSocket.get();
                sk.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
            Log.d(TAG, "MainSocketClientService releaseLastSocket e= " + e.getMessage());
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mReadThread != null) {
            mReadThread.release();
        }
        if (mSocket != null) {
            releaseLastSocket(mSocket);
        }
        destroyInstance();
    }
}

這個是獲取設備信息的工具類,只是作測試用的
package com.android.clientserver;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.util.Log;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

/**
 * Created by Administrator on 2018/5/19.
 */

public class DeviceUtils {

    private static final String TAG = "DeviceUtils";

    public static String getWlanMac() {
        try {
            Log.d(TAG, "getWlanMac:" + loadFileAsString("/sys/class/net/wlan0/address").toUpperCase().substring(0, 17));
            return loadFileAsString("/sys/class/net/wlan0/address").toUpperCase().substring(0, 17);
        } catch (Exception e) {
            Log.e(TAG, "open sys/class/net/eth0/address failed : " + e);
            return "";
        }
    }

    private static String loadFileAsString(String filePath) throws IOException {
        StringBuffer sb = new StringBuffer(1000);
        BufferedReader br = new BufferedReader(new FileReader(filePath));
        char[] buf = new char[1024];
        int numRead = 0;
        while ((numRead = br.read(buf)) != -1) {
            String readData = String.valueOf(buf, 0, numRead);
            sb.append(readData);
        }
        br.close();
        return sb.toString();
    }

    /**
     * 獲取版本名稱
     *
     * @param context 上下文
     * @return 版本名稱
     */
    public static String getVersionName(Context context) {
        // 獲取包管理器
        PackageManager pm = context.getPackageManager();
        // 獲取包信息
        try {
            PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
            // 返回版本名稱
            return packageInfo.versionName;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 獲取版本號
     *
     * @param context 上下文
     * @return 版本號
     */
    public static int getVersionCode(Context context) {
        // 獲取包管理器
        PackageManager pm = context.getPackageManager();
        // 獲取包信息
        try {
            PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
            // 返回版本號
            return packageInfo.versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * 獲取App的名稱
     *
     * @param context 上下文
     * @return App名稱
     */
    public static String getAppName(Context context) {
        // 獲取包管理器
        PackageManager pm = context.getPackageManager();
        // 獲取包信息
        try {
            PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
            // 獲取應用信息
            ApplicationInfo applicationInfo = packageInfo.applicationInfo;
            //獲取labelRes
            int labelRes = applicationInfo.labelRes;
            // 返回App的名稱
            return context.getResources().getString(labelRes);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}

步驟二:創建一個SocketServer Demo 並 編寫服務端代碼

MainSocketServer.java

package com.android.socketserver;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

/**
 * Created by Administrator on 2018/5/19.
 */

public class MainSocketServer extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "MainSocketServer";

    String abc = "{ \"data\": {\"cmd\": \"reboot\", \"time\": 3}}";

    private Button increase_voice_btn;
    private Button reduce_voice_btn;
    private Button shutdown_btn;
    private Button reboot_btn;
    private Button increase_brightness_btn;
    private Button reduce_brightness_btn;
    private Button display_machine_parameters_btn;
    private TextView display_machine_parameters_tv;

    //啓動服務端端口服務端IP
    private SocketServer server = new SocketServer(12345);

    private StringBuilder stringBuilder;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        stringBuilder = new StringBuilder();
        // socket服務端開始監聽
        server.beginListen();

        // socket收到消息線程
        SocketServer.serverHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                stringBuilder.append(msg.obj.toString());
                stringBuilder.append("\r\n");
                display_machine_parameters_tv.setText(stringBuilder);
            }
        };
    }

    private void initView() {
        increase_voice_btn = (Button) findViewById(R.id.increase_voice_btn);
        reduce_voice_btn = (Button) findViewById(R.id.reduce_voice_btn);
        shutdown_btn = (Button) findViewById(R.id.shutdown_btn);
        reboot_btn = (Button) findViewById(R.id.reboot_btn);
        increase_brightness_btn = (Button) findViewById(R.id.increase_brightness_btn);
        reduce_brightness_btn = (Button) findViewById(R.id.reduce_brightness_btn);
        display_machine_parameters_btn = (Button) findViewById(R.id.display_machine_parameters_btn);
        display_machine_parameters_tv = (TextView) findViewById(R.id.display_machine_parameters_tv);
        initListener();
    }

    private void initListener() {
        increase_voice_btn.setOnClickListener(this);
        reduce_voice_btn.setOnClickListener(this);
        shutdown_btn.setOnClickListener(this);
        reboot_btn.setOnClickListener(this);
        increase_brightness_btn.setOnClickListener(this);
        reduce_brightness_btn.setOnClickListener(this);
        display_machine_parameters_btn.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.increase_voice_btn:
                // 發送指令,把音量調成100
                String increaseVoice = "{ \"data\": { \"cmd\": \"increaseVoice\", \"increaseVolume\":100}}" + "#end#";
                server.sendMessage(increaseVoice);
                break;
            case R.id.reduce_voice_btn:
                // 發送指令,把音量調成0
                String reduceVoice = "{ \"data\": { \"cmd\": \"reduceVoice\", \"reduceVolume\":0}}" + "#end#";
                server.sendMessage(reduceVoice);
                break;
            case R.id.shutdown_btn:
                // 發送指令 3秒後關閉機器
                String shutdown = "{ \"data\": { \"cmd\": \"shutdown\", \"shutdownTime\":3}}" + "#end#";
                server.sendMessage(shutdown);
                break;
            case R.id.reboot_btn:
                // 發送指令 3秒後重啓機器
                String reboot = "{ \"data\": { \"cmd\": \"reboot\", \"rebootTime\":3}}" + "#end#";
                server.sendMessage(reboot);
                break;
            case R.id.increase_brightness_btn:
                // 發送指令,把亮度調成100
                String increaseBrightness = "{ \"data\": { \"cmd\": \"increaseBrightness\", \"addBrightnessValue\":100}}" + "#end#";
                server.sendMessage(increaseBrightness);
                break;
            case R.id.reduce_brightness_btn:
                // 發送指令,把亮度調成100
                String reduceBrightness = "{ \"data\": { \"cmd\": \"reduceBrightness\", \"reduceBrightnessValue\":0}}" + "#end#";
                server.sendMessage(reduceBrightness);
                break;
            case R.id.display_machine_parameters_btn:
                // 發送指令 獲取板卡參數
                String machineParameters = "{ \"data\": { \"cmd\": \"machineParameters\"}}" + "#end#";
                server.sendMessage(machineParameters);
                break;
        }
    }
}
 

     SocketServer封裝類

    

package com.android.socketserver;

import android.os.Handler;
import android.os.Message;
import android.util.Log;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;

/**
 * Created by Administrator on 2018/5/19.
 */

public class SocketServer {

    private static final String TAG = "SocketServer";

    private ServerSocket server;
    private Socket mSocket;
    private InputStream in;
    private String getClientData = "";
    private boolean isClient = false;
    public static Handler serverHandler;

    /**
     * 初始化服務端
     *
     * @param port
     */
    public SocketServer(int port) {
        try {
            server = new ServerSocket(port);
            isClient = true;
        } catch (IOException e) {
            e.printStackTrace();
            Log.d(TAG, "SocketServer IOException e = " + e.getMessage());
        }
    }

    /**
     * socket監聽數據
     */
    public void beginListen() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Log.d(TAG, "SocketServer beginListen......");
                    // 接受請求
                    if (server != null && isClient == true) {
                        mSocket = server.accept();
                    }
                    // 得到輸入流
                    in = mSocket.getInputStream();                    // 實現數據循環接收
                    while (mSocket.isConnected()) {
                        byte[] buffer = new byte[1024 * 4];
                        int length = in.read(buffer);
                        getClientData = new String(Arrays.copyOf(buffer, length)).trim();
                        Log.d(TAG, "SocketServer beginListen getClientData = " + getClientData);
                        if (getClientData != null && !"".equals(getClientData) && getClientData != "exit") {
                            returnMessage(getClientData);
                        } else if (getClientData == null || getClientData == "exit") {
                            break;
                        }
                    }
                } catch (IOException e) {
                    Log.d(TAG, "SocketServer beginListen IOException e = " + e.getMessage());
                    mSocket.isClosed();
                }
            }
        }).start();
    }

    /**
     * socket服務端發送指令給客戶端
     *
     * @param toClientCommand
     */
    public void sendMessage(final String toClientCommand) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    if (mSocket != null && !mSocket.isClosed() && toClientCommand != null) {
                        Log.d(TAG, "SocketServer sendMessage toClientCommand = " + toClientCommand);
                        PrintWriter out = new PrintWriter(mSocket.getOutputStream());
                        out.print(toClientCommand);
                        out.flush();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    Log.d(TAG, "SocketServer sendMessage IOException e = " + e.getMessage());
                }
            }
        });
        thread.start();
    }

    /**
     * socket服務端得到返回的數據併發送到主界面
     *
     * @param getClientData
     */
    public void returnMessage(String getClientData) {
        Message msg = new Message();
        msg.obj = getClientData;
        serverHandler.sendMessage(msg);
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章