大家好,欢迎来到IT知识分享网。
背景:
两个设备,其中一个设备开启热点,另外一个手设备接热点,两个设备间进行数据通信(不需要流量)。原理:开热点的设备相当于路由器,作为服务端,连接的设备作为客户端,获取路由器的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, "发送失败"); } } }); }
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, "发送失败"); } } }); }
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/147305.html