最近对原来写的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 octetof {@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 specifiedby the

{@code SocketAddress} object with the given timeout. This methodwill 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中实现发送命令的方法,代码如下:

publicvoidsendCameraCmdThread(byte[]cmd){if(cmd==null)return;Log.i("TEST","====================================sendCameraCmd");try{socketClientThread.sendUrgentData();socketClientThread.sendCameraCmdThread(cmd);}catch(Exceptione){//重新连接的代码e.printStackTrace();socketClientThread=newSocketClientThread();socketClientThread.setByteArrCommand(cmd);socketClientThread.start();}}


2.SocketClient重新连接后,如何重发命令?

因为SocketClient重新连接,所以必须在SocketClient重新连接后才能重发命令。在线程中增加public voidsetCommandArr(byte[] cmds) 方法。具体代码如下:

@Overridepublicvoidrun(){super.run();Timertimer=newTimer();try{if(clientSocket==null){clientSocket=newSocket();clientSocket.connect(newInetSocketAddress(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=newbyte[56];intsize=0;timer.schedule(newTimerTask(){@Overridepublicvoidrun(){if(cmdArr!=null){for(inti=0;i<cmdArr.length;i++){sendCameraCmdThread(cmdArr[i]);}}}},100);Log.i("TEST","======================>starttime");while(clientSocket!=null&&(size=cameraInputStream.read(buffers))!=-1){Log.i("TEST","===================>receivemsg:"+Utils.bytesToHexString(buffers));}}catch(Exceptione){}}else{Log.e("TEST","=================>cameraInputStreamisnull");}}else{}}}catch(Exceptione){}finally{Log.i("TEST","===================>ClientClose!");if(timer!=null){timer.cancel();}if(cameraOutputStream!=null){try{cameraOutputStream.close();cameraOutputStream=null;}catch(IOExceptione){e.printStackTrace();}}if(cameraInputStream!=null){try{cameraInputStream.close();cameraInputStream=null;}catch(IOExceptione){e.printStackTrace();}}if(clientSocket!=null){try{clientSocket.close();clientSocket=null;}catch(IOExceptione){e.printStackTrace();}}}}

在SocketClient重新连接后,则使用Timer延时100毫秒后,则发送命令。这样就能保证发送的命令成功。


附件:http://down.51cto.com/data/2368202