最近对原来写的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毫秒后,则发送命令。这样就能保证发送的命令成功。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。