最近对原来写的SocketClient代码进行优化,从整体架构到具体细节,修改的地方比较多。今天有时间把SocketClient的相关知识整理一下。如果有错误的地方,还望指正!!!
创新互联专注于盘锦网站建设服务及定制,我们拥有丰富的企业做网站经验。 热诚为您提供盘锦营销型网站建设,盘锦网站制作、盘锦网页设计、盘锦网站官网定制、小程序制作服务,打造盘锦网络公司原创品牌,更为您提供盘锦网站排名全网营销落地服务。
一、整体流程:
描述如下:
1. 在Android环境下,SocketClient长连接,需要使用service。
2. SocketManagerService是在APK启动时启动。
3. SocketManagerService启动时则SocketClientThread也启动。
4. View调用SocketManagerService的sendCmd方法发送命令。
5. 如果SocketClient连接断开,则重新建立连接,并且发送该命令。
6. 状态返回则通过自定义Listener实现。
二、预备知识:
1. 判断SocketClient是否与SocketServer连接:
1) . public void sendUrgentData(int value) throws IOException
源码注释:
Sends the given single byte data which is represented by the lowest octet of {@code value} as "TCP urgent data".
翻译:
发送给定的代表最低字节码值的单字节数据,作为TCP紧急数据 。
个人理解:
该方法用于判断SocketClient是否与SocketServer连接。
2.关于SocketClient的超时的理解:
1) . public void connect(SocketAddress remoteAddr, int timeout) throws IOException
源码注释:
Connects this socket to the remote host address and port number specified by the
{@code SocketAddress} object with the given timeout. This method will block indefinitely if the timeout is set to zero.
翻译:
在有超时的情况下,socket连接指定地远程主机的地址和端口。如果timeout是0,则方法永远阻塞。
个人理解:
该方法的作用是SocketClient与SocketServer之间建立连接时的超时判断。
2). public synchronized void setSoTimeout(int timeout) throws SocketException
源码注释:
Sets this socket's {@link SocketOptions#SO_TIMEOUT read timeout} in milliseconds.
Use 0 for no timeout. To take effect, this option must be set before the blocking method was called.
翻译:
设置socketClient读的超时时间。0表示没有超时。该方法必须在阻塞方法之间调用。
个人理解:
InputStream的read方法,在timeout的时间内没有接收到数据,则超时。超时后read方法停止阻塞状态。
三、问题解答 :
1. 如何实现SocketClient的重新连接?
1). SocketClient设置setSoTime(int timeout) 当超时后,则read停止阻塞,所以线程停止运行。我代码中timeout设置为30分钟。
2). 在SocketManagerService中实现发送命令的方法,代码如下:
public void sendCameraCmdThread(byte[] cmd) { if (cmd == null) return; Log.i("TEST","====================================sendCameraCmd"); try { socketClientThread.sendUrgentData(); socketClientThread.sendCameraCmdThread(cmd); } catch (Exception e) { //重新连接的代码 e.printStackTrace(); socketClientThread = new SocketClientThread(); socketClientThread.setByteArrCommand(cmd); socketClientThread.start(); } }
2. SocketClient重新连接后,如何重发命令?
因为SocketClient重新连接,所以必须在SocketClient重新连接后才能重发命令。在线程中增加 public void setCommandArr(byte[] cmds) 方法。具体代码如下:
@Override public void run() { super.run(); Timer timer = new Timer(); try { if (clientSocket == null) { clientSocket = new Socket(); clientSocket.connect(new InetSocketAddress(IP,PORT),5000); if (clientSocket!=null) { clientSocket.setReceiveBufferSize(SOCKET_RECV_BUFFER_SIZE); clientSocket.setSoTimeout(30*60*1000); cameraOutputStream = clientSocket.getOutputStream(); cameraInputStream = clientSocket.getInputStream(); if (cameraInputStream!=null) { try { byte[] buffers = new byte[56]; int size = 0; timer.schedule(new TimerTask() { @Override public void run() { if(cmdArr!=null) { for (int i = 0; i < cmdArr.length; i++) { sendCameraCmdThread(cmdArr[i]); } } } }, 100); Log.i("TEST","======================>start time"); while (clientSocket!=null&&(size = cameraInputStream.read(buffers))!= -1) { Log.i("TEST", "===================> receive msg: " +Utils.bytesToHexString(buffers)); } } catch (Exception e) { } } else { Log.e("TEST","=================> cameraInputStream is null"); } } else { } } } catch (Exception e) { } finally { Log.i("TEST","===================>Client Close!"); if(timer!=null) { timer.cancel(); } if (cameraOutputStream!=null) { try { cameraOutputStream.close(); cameraOutputStream=null; } catch (IOException e) { e.printStackTrace(); } } if (cameraInputStream!=null) { try { cameraInputStream.close(); cameraInputStream = null; } catch (IOException e) { e.printStackTrace(); } } if (clientSocket!=null) { try { clientSocket.close(); clientSocket=null; } catch (IOException e) { e.printStackTrace(); } } } }
在SocketClient重新连接后,则使用Timer延时100毫秒后,则发送命令。这样就能保证发送的命令成功。