安卓热点通讯的实现(Socket通讯)

背景:
两个设备,其中一个设备开启热点,另外一个手设备接热点,两个设备间进行数据通信(不需要流量)。原理:开热点的设备相当于路由器,作为服务端,连接的设备作为客户端,获取路由器的IP建立Socket 连接,开始双方通信。
实现:
一、服务端
1.创建一个SocketAdmin来管理通讯连接

public class SocketAdmin {
    private final static String TAG = "SocketAdmin";

    public static SocketAdmin socketAdmin;

    private EncryptEcbBean mEncryptEcbBean;

    private ConnectThread mConnectThread;

    private ListenerThread mListenerThread;

    private WifiApInfo mWifiApInfo;

    private boolean mIsHeart = false; // 心跳线程运行状态

    private boolean mIsReceive = false; // 心跳监控线程状态

    private long mStartTime = 0; // 接收心跳标志位

    private Thread mHeartThread;

    private Thread mReceiveThread;

    public static SocketAdmin getInstance() {
        if (socketAdmin == null) {
            socketAdmin = new SocketAdmin();
        }
        return socketAdmin;
    }

    public SocketAdmin() {
        getEncryptBean();
        mWifiApInfo = new WifiApInfo();
    }

    @SuppressLint("HandlerLeak")
    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage( Message msg) {
            String message = "";
            String data = "";
            switch (msg.what) {
                // 有设备正在连接热点
                case WifiAp.DEVICE_CONNECTING:
                    Bundle bundle = msg.getData();
                    String ip = bundle.getString("ip");
                    Log.i(TAG, "ip:" + ip + "尝试连接");
                    if (mConnectThread != null) {
                        stopConnectThread();
                    }
                    if (mListenerThread != null) {
                        startConnectThread(mListenerThread.getSocket(), this);
                    }
                    break;
                // 有设备连上热点
                case WifiAp.DEVICE_CONNECTED:
                    Log.i(TAG, "设备连接成功");
                    mWifiApInfo.setRemoteControlAp(1);
                    startHeartThread();
                    startReceiveThread();
                    break;
                // 发送消息成功
                case WifiAp.SEND_MSG_SUCCESS:
                    message = msg.getData().getString("MSG");
                    data = getMsg(message);
                    Log.i(TAG, "发送消息成功:" + data);
                    break;
                // 发送消息失败
                case WifiAp.SEND_MSG_ERROR:
                    message = msg.getData().getString("MSG");
                    data = getMsg(message);
                    Log.i(TAG, "发送消息失败:" + data);
                    break;
                // 获取新消息
                case WifiAp.GET_MSG:
                    message = msg.getData().getString("MSG");
                    data = getMsg(message);
                    Log.i(TAG, "收到消息:" + data);
                    if (Objects.equals(data, WifiAp.HEART_SERVER)) {
                        mStartTime = System.currentTimeMillis();
                    }
                    break;
            }
        }
    };

    /**
     * 心跳线程
     */
    private void getHeardThread() {
        stopHeartThread();
        mIsHeart = true;
        mHeartThread = new Thread(new Runnable() {
            @Override
            public void run() {
                long startTime = System.currentTimeMillis();
                while (mIsHeart) {
                    // 每隔4s发送心跳
                    if (System.currentTimeMillis() - startTime > 4000) {
                        startTime = System.currentTimeMillis();
                        sendMsg(WifiAp.HEART_SERVER);
                    }
                }
            }
        });
    }

    /**
     * 心跳接收线程
     */
    private void getReceiveThread() {
        stopReceiveThread();
        mIsReceive = true;
        mReceiveThread = new Thread(new Runnable() {
            @Override
            public void run() {
                mStartTime = System.currentTimeMillis();
                while (mIsReceive) {
                    // 若超时未检测到客户端发送的心跳,则变更通讯连接状态
                    if (System.currentTimeMillis() - mStartTime > 5000) {
                        Log.i(TAG, "Socket断开连接");
                        mIsReceive = false;
                        // 变更通讯连接状态为已断开
                        mWifiApInfo.setRemoteControlAp(2);
                        stopHeartThread();
                        stopConnectThread();
                    }
                }
            }
        });
    }

    public ConnectThread getConnectThread() {
        return mConnectThread;
    }

    public ListenerThread getListenerThread() {
        return mListenerThread;
    }

    public WifiApInfo getWifiApInfo() {
        return mWifiApInfo;
    }

    public void setWifiApInfo(WifiApInfo wifiApInfo) {
        this.mWifiApInfo = wifiApInfo;
    }

    public void setStartTime(long mStartTime) {
        this.mStartTime = mStartTime;
    }

    /**
     * 初始化当前热点信息
     */
    public void initWifiIo() {
        if (WifiAdmin.getInstance().isApOn()) {
            WifiConfiguration config = WifiAdmin.getInstance().getWifiApConfiguration();
            if (config != null) {
                mWifiApInfo.setWifiInfo(config.SSID, config.preSharedKey);
            } else {
                mWifiApInfo.setWifiInfo("", "");
            }
        } else {
            mWifiApInfo.setWifiInfo("", "");
        }
    }

    /**
     * 开启Socket连接监听线程
     */
    public void startListenerThread() {
        stopListenerThread();
        mListenerThread = null;
        mListenerThread = new ListenerThread(WifiAp.PORT, mHandler);
        mListenerThread.start();
    }

    /**
     * 关闭Socket连接监听线程
     */
    public void stopListenerThread() {
        if (mListenerThread != null) {
            mListenerThread.setRunning(false);
            try {
                mListenerThread.join();
            } catch (InterruptedException i) {
                Log.e(TAG, i.toString());
            }
            mListenerThread.close();
        }
    }

    /**
     * 开启Socket连接线程
     *
     */
    public void startConnectThread(Socket socket, Handler handler) {
        stopConnectThread();
        mConnectThread = null;
        mConnectThread = new ConnectThread(socket, handler);
        mConnectThread.start();
    }

    /**
     * 关闭Socket连接线程
     *
     */
    public void stopConnectThread() {
        if (mConnectThread != null) {
            mConnectThread.setRunning(false);
            try {
                mConnectThread.join();
            } catch (InterruptedException i) {
                Log.e(TAG, i.toString());
            }
            mConnectThread.close();
        }
    }

    /**
     * 初始化对称加密算法
     */
    private boolean getEncryptBean() {
        if (mEncryptEcbBean != null) {
            return true;
        }
        try {
            mEncryptEcbBean = new EncryptEcbBean();
            return true;
        } catch (Exception e) {
            Log.e(TAG, e.toString());
            Log.i(TAG, "加密初始化失败");
            return false;
        }
    }

    /**
     * 开启心跳线程
     */
    public void startHeartThread() {
        getHeardThread();
        mHeartThread.start();
    }

    /**
     * 关闭心跳线程
     */
    public void stopHeartThread() {
        mIsHeart = false;
        try {
            if (mHeartThread != null) {
                mHeartThread.join();
                mHeartThread = null;
            }
        } catch (InterruptedException i) {
            Log.e(TAG, i.toString());
        }
    }

    /**
     * 开启心跳监控线程
     */
    public void startReceiveThread() {
        getReceiveThread();
        mReceiveThread.start();
    }

    /**
     * 关闭心跳监控线程
     */
    public void stopReceiveThread() {
        mIsReceive = false;
        try {
            if (mReceiveThread != null) {
                mReceiveThread.join();
                mReceiveThread = null;
            }
        } catch (InterruptedException i) {
            Log.e(TAG, i.toString());
        }
    }

    /**
     * 发送消息
     * @param msg 消息
     * @return 结果
     */
    public boolean sendMsg(String msg) {
        if (!getEncryptBean()) {
            return false;
        }
        if (mConnectThread == null) {
            Log.e(TAG, "发送消息:mConnectThread未初始化");
            return false;
        }
        try {
            byte[] msgBytes = msg.getBytes(StandardCharsets.UTF_8);
            byte[] encrypted = mEncryptEcbBean.encrypt(msgBytes);
            String data = ByteUtils.bytesToHexString(encrypted);
            Log.i(TAG, "encrypted(加密):" + data);
            mConnectThread.sendData(data);
            return true;
        } catch  (Exception e) {
            Log.e(TAG, e.toString());
            return false;
        }
    }

    /**
     * 获取消息
     * @param msg 消息(加密)
     * @return 消息(解密)
     */
    public String getMsg(String msg) {
        if (!getEncryptBean()) {
            return "";
        }
        try {
            byte[] bytes1 = ByteUtils.hexStringToBytes(msg);
            byte[] bytes2 = mEncryptEcbBean.decrypt(bytes1);
            return new String(bytes2, StandardCharsets.UTF_8);
        } catch  (Exception e) {
            Log.e(TAG, e.toString());
            return "";
        }
    }

    public void close() {
        mWifiApInfo.setRemoteControlAp(2);

        stopHeartThread();
        stopReceiveThread();
        stopConnectThread();
        stopListenerThread();

        mConnectThread = null;
        mListenerThread = null;

        mHandler.removeCallbacksAndMessages(null);
    }
}

其中对发送和接收的数据使用了对称加密算法,如不需要直接删除即可。

2.WifiAp 如下。

public class WifiAp {
    public static final int PORT = 54321;

    public static final int DEVICE_CONNECTING = 1; // 有设备正在连接热点

    public static final int DEVICE_CONNECTED = 2; // 有设备连上热点

    public static final int SEND_MSG_SUCCESS = 3; // 发送消息成功

    public static final int SEND_MSG_ERROR = 4; // 发送消息失败

    public static final int GET_MSG = 6; // 获取新消息

    public final static String HEART_SERVER = "HEART_SERVER"; // 心跳
}

3.ListenerThread 通讯监听线程如下。

public class ListenerThread extends Thread {
    private final static String TAG = "ListenerThread";

    private ServerSocket serverSocket = null;

    private Handler handler;

    private Socket socket;

    private boolean isRunning = true;

    public ListenerThread(int port, Handler handler) {
        setName(TAG);
        this.handler = handler;
        try {
            serverSocket = new ServerSocket(port);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void setRunning(boolean running) {
        isRunning = running;
    }

    @Override
    public void run() {
        while (isRunning) {
            try {
                Log.i(TAG, "阻塞");
                //阻塞,等待设备连接
                if (serverSocket != null)
                    socket = serverSocket.accept();
                String ip = socket.getInetAddress().getHostAddress();
                Log.i(TAG, "ip:" + ip + "设备尝试连接");
                Message message = Message.obtain();
                message.what = WifiAp.DEVICE_CONNECTING;
                Bundle bundle = new Bundle();
                bundle.putString("ip", ip);
                message.setData(bundle);
                handler.sendMessage(message);
            } catch (IOException e) {
                Log.i(TAG, "error:" + e.getMessage());
                e.printStackTrace();
            }
        }
    }

    public Socket getSocket() {
        return socket;
    }

    public void close() {
        try {
            isRunning = false;
            if (socket != null) {
                socket.close();
            }
            if (serverSocket != null) {
                serverSocket.close();
            }
            if (handler != null) {
                handler.removeCallbacksAndMessages(null);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

4.连接线程如下。

public class ConnectThread extends Thread {
    private final static String TAG = "ConnectThread";

    private final Socket socket;

    private Handler handler;

    private InputStream inputStream;

    private OutputStream outputStream;

    private boolean isRunning = true;

    public ConnectThread(Socket socket, Handler handler) {
        setName(TAG);
        Log.i(TAG, TAG);
        this.socket = socket;
        this.handler = handler;
    }

    public void setRunning(boolean running) {
        isRunning = running;
    }

    @Override
    public void run() {
        if (socket == null) {
            return;
        }
        handler.sendEmptyMessage(WifiAp.DEVICE_CONNECTED);
        try {
            //获取数据流
            inputStream = socket.getInputStream();
            outputStream = socket.getOutputStream();

            byte[] buffer = new byte[1024];
            int bytes;
            while (isRunning) {
                //读取数据
                bytes = inputStream.read(buffer);
                if (bytes > 0) {
                    final byte[] data = new byte[bytes];
                    System.arraycopy(buffer, 0, data, 0, bytes);

                    Message message = Message.obtain();
                    message.what = WifiAp.GET_MSG;
                    Bundle bundle = new Bundle();
                    bundle.putString("MSG", new String(data));
                    message.setData(bundle);
                    handler.sendMessage(message);

                    Log.i(TAG, "读取到数据:" + new String(data));
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送数据
     */
    public void sendData(String msg) {
        Log.i(TAG, "发送数据:" + (outputStream == null));
        if (outputStream != null) {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        outputStream.write(msg.getBytes());
                        Log.i(TAG, "发送消息:" + msg);
                        Message message = Message.obtain();
                        message.what = WifiAp.SEND_MSG_SUCCESS;
                        Bundle bundle = new Bundle();
                        bundle.putString("MSG", new String(msg));
                        message.setData(bundle);
                        handler.sendMessage(message);
                    } catch (IOException e) {
                        e.printStackTrace();
                        Message message = Message.obtain();
                        message.what = WifiAp.SEND_MSG_ERROR;
                        Bundle bundle = new Bundle();
                        bundle.putString("MSG", new String(msg));
                        message.setData(bundle);
                        handler.sendMessage(message);
                    }
                }
            });
            thread.start();
        }
    }
    
    public boolean close() {
        try {
            isRunning = false;
            if (socket != null) {
                socket.close();
            }
            if (inputStream != null) {
                inputStream.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
            if (handler != null) {
                handler.removeCallbacksAndMessages(null);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
}

5.在确保热点打开的情况下,只需在MainActivity中开启监听线程即可。

SocketAdmin.getInstance().startListenerThread()

6.在MainActivity中发送数据

    /**
     * 判断socket是否连接
     */
    private boolean isSocketEnabled() {
        if (SocketAdmin.getInstance().getWifiApInfo().getRemoteControlAp() != 1) {
            ToastUtil.showToast("未建立通信连接,请先连接", 2000);
            return false;
        }
        return true;
    }
    
    private void initClick() {
        mBinding.btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!isSocketEnabled()) {
                    return;
                }
                String msg = "test";
                if (SocketAdmin.getInstance().sendMsg(msg)) {
                    Log.i(TAG, "发送成功");
                } else {
                    Log.i(TAG, "发送失败");
                }
            }
        });
    }

二、客户端
1.创建一个SocketAdmin来管理通讯连接

public class SocketAdmin {
    private final static String TAG = "SocketAdmin";

    public static SocketAdmin socketAdmin;

    private EncryptEcbBean mEncryptEcbBean;

    private ConnectThread mConnectThread;

    private ListenerThread mListenerThread;

    private WifiApInfo mWifiApInfo;

    private boolean mIsHeart = false; // 心跳线程运行状态

    private boolean mIsReceive = false; // 心跳监控线程状态


    private long mStartTime = 0; // 接收心跳标志位

    private Thread mHeartThread;

    private Thread mReceiveThread;

    public static SocketAdmin getInstance() {
        if (socketAdmin == null) {
            socketAdmin = new SocketAdmin();
        }
        return socketAdmin;
    }

    public SocketAdmin() {
        getEncryptBean();
        mWifiApInfo = new WifiApInfo();
    }

    @SuppressLint("HandlerLeak")
    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage( Message msg) {
            String message = "";
            String data = "";
            switch (msg.what) {
                case WifiAp.DEVICE_CONNECTED:
                    Log.i(TAG, "设备连接成功");
                    mWifiApInfo.setRemoteControlAp(1, false);
                    startReceiveThread();
                    break;
                case WifiAp.SEND_MSG_SUCCESS:
                    message = msg.getData().getString("MSG");
                    data = getMsg(message);
                    Log.i(TAG, "发送消息成功:" + data);
                    break;
                case WifiAp.SEND_MSG_ERROR:
                    message = msg.getData().getString("MSG");
                    data = getMsg(message);
                    Log.i(TAG, "发送消息失败:" + data);
                    break;
                case WifiAp.GET_MSG:
                    message = msg.getData().getString("MSG");
                    data = getMsg(message);
                    Log.i(TAG, "收到消息:" + data);
                    if (Objects.equals(data, WifiAp.HEART_SERVER)) {
                        setStartTime(System.currentTimeMillis());
                        sendMsg(WifiAp.HEART_SERVER);
                    }
                    break;
            }
        }
    };

    private void getHeardThread() {
        stopHeartThread();
        mIsHeart = true;
        mHeartThread = new Thread(new Runnable() {
            @Override
            public void run() {
                long startTime = System.currentTimeMillis();
                while (mIsHeart) {
                    if (System.currentTimeMillis() - startTime > 4000) {
                        startTime = System.currentTimeMillis();
                        sendMsg(WifiAp.HEART_SERVER);
                        mWifiApInfo.setReConnect(false);
                    }
                }
            }
        });
    }

    private void getReceiveThread() {
        stopReceiveThread();
        mIsReceive = true;
        mReceiveThread = new Thread(new Runnable() {
            @Override
            public void run() {
                mStartTime = System.currentTimeMillis();
                while (mIsReceive) {
                    if (System.currentTimeMillis() - mStartTime > 5000) {
                        Log.i(TAG, "Socket断开连接");
                        mIsReceive = false;
                        mWifiApInfo.setRemoteControlAp(2, false);
                        stopConnectThread();
                    }
                }
            }
        });
    }

    public WifiApInfo getWifiApInfo() {
        return mWifiApInfo;
    }

    public ConnectThread getConnectThread() {
        return mConnectThread;
    }

    public ListenerThread getListenerThread() {
        return mListenerThread;
    }

    public void setStartTime(long mStartTime) {
        this.mStartTime = mStartTime;
    }

    public void startListenerThread(Handler handler) {
        stopListenerThread();
        mListenerThread = null;
        mListenerThread = new ListenerThread(WifiAp.PORT, handler);
        mListenerThread.start();
    }

    public void stopListenerThread() {
        if (mListenerThread != null) {
            mListenerThread.setRunning(false);
            try {
                mListenerThread.join();
            } catch (InterruptedException i) {
                Log.e(TAG, i.toString());
            }
            mListenerThread.close();
        }
    }

    public void startConnectThread(Socket socket) {
        mConnectThread = null;
        mConnectThread = new ConnectThread(socket, mHandler);
        mConnectThread.start();
    }

    public void stopConnectThread() {
        if (mConnectThread != null) {
            mConnectThread.setRunning(false);
            try {
                mConnectThread.join();
            } catch (InterruptedException i) {
                Log.e(TAG, i.toString());
            }
            mConnectThread.close();
        }
    }

    private boolean getEncryptBean() {
        if (mEncryptEcbBean != null) {
            return true;
        }
        try {
            mEncryptEcbBean = new EncryptEcbBean();
            return true;
        } catch (Exception e) {
            Log.e(TAG, e.toString());
            Log.i(TAG, "加密初始化失败");
            return false;
        }
    }

    /**
     * 开启心跳线程
     */
    public void startHeartThread() {
        getHeardThread();
        mHeartThread.start();
    }

    /**
     * 关闭心跳线程
     */
    public void stopHeartThread() {
        mIsHeart = false;
        try {
            if (mHeartThread != null) {
                mHeartThread.join();
                mHeartThread = null;
            }
        } catch (InterruptedException i) {
            Log.e(TAG, i.toString());
        }
    }

    /**
     * 开启心跳监控线程
     */
    public void startReceiveThread() {
        getReceiveThread();
        mReceiveThread.start();
    }

    /**
     * 关闭心跳监控线程
     */
    public void stopReceiveThread() {
        mIsReceive = false;
        try {
            if (mReceiveThread != null) {
                mReceiveThread.join();
                mReceiveThread = null;
            }
        } catch (InterruptedException i) {
            Log.e(TAG, i.toString());
        }
    }

    /**
     * 发送消息
     * @param msg 消息
     * @return 结果
     */
    public boolean sendMsg(String msg) {
        if (!getEncryptBean()) {
            return false;
        }
        if (mConnectThread == null) {
            Log.e(TAG, "发送消息:mConnectThread未初始化");
            return false;
        }
        try {
            byte[] msgBytes = msg.getBytes(StandardCharsets.UTF_8);
            byte[] encrypted = mEncryptEcbBean.encrypt(msgBytes);
            String data = ByteUtils.bytesToHexString(encrypted);
            Log.i(TAG, "encrypted(加密):" + data);
            mConnectThread.sendData(data);
            return true;
        } catch  (Exception e) {
            Log.e(TAG, e.toString());
            return false;
        }
    }

    /**
     * 获取消息
     * @param msg 消息(加密)
     * @return 消息(解密)
     */
    public String getMsg(String msg) {
        if (!getEncryptBean()) {
            return "";
        }
        try {
            byte[] bytes1 = ByteUtils.hexStringToBytes(msg);
            byte[] bytes2 = mEncryptEcbBean.decrypt(bytes1);
            return new String(bytes2, StandardCharsets.UTF_8);
        } catch  (Exception e) {
            Log.e(TAG, e.toString());
            return "";
        }
    }

    public void close() {
        mWifiApInfo.setRemoteControlAp(2, false);

        stopConnectThread();
        stopListenerThread();
        stopHeartThread();
        stopReceiveThread();

        mConnectThread = null;
        mListenerThread = null;
    }
}

2.ConnectThread线程和上面一致,客户端无需使用ListenerThread线程。

3.确保已连接指定热点的情况下,在MainActivity中直接调用连接线程即可。

	private void connectSocket() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Socket socket = new Socket(WifiAdmin.getInstance().getWifiRouteIPAddress(), WifiAp.PORT);
                    SocketAdmin.getInstance().startConnectThread(socket);
                } catch (IOException e) {
                    e.printStackTrace();
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            ToastUtil.showToast("Socket通信连接失败", 2000);
                        }
                    });

                }
            }
        }).start();
    }

	/**
     * wifi获取已连接网络路由ip地址
     *
     */
    public String getWifiRouteIPAddress() {
   		WifiManager wifiManager = (WifiManager) Utils.getApp().getApplicationContext().getSystemService(Context.WIFI_SERVICE)
        DhcpInfo dhcpInfo = wifiManager.getDhcpInfo();
        String routeIp = Formatter.formatIpAddress(dhcpInfo.gateway);
        Log.i("route ip", "wifi route ip:" + routeIp);

        return routeIp;
    }

4.在MainActivity中发送数据

    /**
     * 判断socket是否连接
     */
    private boolean isSocketEnabled() {
        if (SocketAdmin.getInstance().getWifiApInfo().getRemoteControlAp() != 1) {
            ToastUtil.showToast("未建立通信连接,请先连接", 2000);
            return false;
        }
        return true;
    }
    
    private void initClick() {
        mBinding.btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!isSocketEnabled()) {
                    return;
                }
                String msg = "test";
                if (SocketAdmin.getInstance().sendMsg(msg)) {
                    Log.i(TAG, "发送成功");
                } else {
                    Log.i(TAG, "发送失败");
                }
            }
        });
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值