Android编程:双工tcp客户端中应用RxJava
本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明.
环境:
主机:WIN10
开发环境:Android Studio 2.2 Preview 3
RxJava版本:2.0.1
RxAndroid版本:2.0.1
说明:
在《Android编程:双工tcp客户端》文中用双线程处理了tcp客户端的发送和接收。现在用RxJava对此客户端代码进行优化:
- 用RxJava创建连接,替代之前的创建连接线程
- 用RxJava断开连接,替代之前的断开连接线程
- 用RxJava推送接收到的网络帧,替代之前的观察者模式
- 用RxJava推送创建成功消息,连接异常中断消息。之前不能推送,只能轮询连接状态
用RxJava实现事件总线, 参考:《RxJava编程:事件总线RxBus》
代码中用了lambda机制,在android studio需要安装插件retrolambda,可以参考安装:
源码:
Events.Java
package com.bazhangkeji.classroom.common; import java.net.DatagramPacket; public class Events { private Events() { } public static class UdpReceiveFrame { public DatagramPacket datagramPacket; } public static class TcpReceiveFrame { public DatagramPacket datagramPacket; } public static class TcpMakeConnectSuccess { } public static class TcpExceptionClose { } }
TcpClient.java
package com.bazhangkeji.classroom.net; import android.util.Log; import com.bazhangkeji.classroom.Config; import com.bazhangkeji.classroom.common.Crc16; import com.bazhangkeji.classroom.common.Events; import com.bazhangkeji.classroom.common.RxBus; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.DatagramPacket; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress; import java.util.ArrayList; import java.util.List; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import io.reactivex.BackpressureStrategy; import io.reactivex.Flowable; import io.reactivex.schedulers.Schedulers; public class TcpClient implements Config, Protocol, Runnable { private static final String TAG_LOG = "TcpClient"; private static final int MAX_FRAME_LENGTH = 2048; private static final int CONNECT_TIME_OUT = 3000; private static TcpClient tcpClient; private boolean isConnected = false; private Socket tcpSocket; private InputStream inputSteam; private OutputStream outputStream; private String serverIp = ""; private int serverPort; private List<NetSendParameter> sendListCache; private List<NetSendParameter> sendList; private ReadWriteLock sendListCacheLock; // 线程锁:当前发送线程全部发送完成后就自锁等待 private final byte[] lockSendThread = new byte[0]; // 线程锁:当前不需要侦听则自锁等待 private final byte[] lockReceiveThread = new byte[0]; public static TcpClient getInstance() { if (tcpClient == null) { tcpClient = new TcpClient(); new Thread(TcpClient.getInstance()).start(); } return tcpClient; } private TcpClient() { sendListCache = new ArrayList<>(); sendList = new ArrayList<>(); sendListCacheLock = new ReentrantReadWriteLock(); new Thread(new SendThread()).start(); } /** * 连接服务器 * @param ip: 服务器ip * @param port: 服务器端口 */ public synchronized void makeConnect(String ip, int port) { if (isConnected) { if (this.serverIp.equals(ip) && this.serverPort == port) { Events.TcpMakeConnectSuccess event = new Events.TcpMakeConnectSuccess(); RxBus.getInstance().send(event); return; } } Flowable.create(e -> { e.onNext(new NetAddress(ip, port)); e.onComplete(); }, BackpressureStrategy.DROP) .observeOn(Schedulers.io()) .subscribe(t -> startMakeConnect((NetAddress)t)); // NetAddress netAddress = new NetAddress(ip, port); // Flowable.create(new FlowableOnSubscribe<NetAddress>() { // @Override // public void subscribe(FlowableEmitter<NetAddress> e) throws Exception { // Log.e(TAG_LOG, "subscribe!!!!!!!!!!!!!!!!!!!"); // e.onNext(netAddress); // e.onComplete(); // } // }, BackpressureStrategy.DROP). // observeOn(Schedulers.io()). // subscribe(new Consumer<NetAddress>() { // @Override // public void accept(NetAddress netAddress1) throws Exception { // Log.e(TAG_LOG, "accept!!!!!!!!!!!!!!!!!!!"); // startMakeConnect(netAddress1); // } // }); } private void startMakeConnect(NetAddress netAddress) { if (isConnected) { tcpSocketClose(); } try { tcpSocket = new Socket(); SocketAddress address = new InetSocketAddress(netAddress.ip, netAddress.port); tcpSocket.connect(address, CONNECT_TIME_OUT); inputSteam = tcpSocket.getInputStream(); outputStream = tcpSocket.getOutputStream(); isConnected = true; serverIp = netAddress.ip; serverPort = netAddress.port; unlockReceiveThread(); Log.e(TAG_LOG, "make connect success!!!!!!!!!!!!!!!!!!!"); Events.TcpMakeConnectSuccess event = new Events.TcpMakeConnectSuccess(); RxBus.getInstance().send(event); } catch (IOException e) { e.printStackTrace(); } } private void tcpSocketClose() { isConnected = false; try { tcpSocket.close(); Log.i(TAG_LOG, "断开连接"); } catch (IOException e) { e.printStackTrace(); } } private void unlockReceiveThread() { synchronized (lockReceiveThread) { lockReceiveThread.notifyAll(); } } /** * 关闭连接 */ public void close() { if (isConnected) { Flowable.create(e -> { e.onNext(""); e.onComplete(); }, BackpressureStrategy.DROP) .observeOn(Schedulers.io()) .subscribe(t -> tcpSocketClose()); } } /** * 当前是否连接. * @return 连接返回true,失败返回false */ public boolean isConnected() { return isConnected; } /** * 得到服务器ip * @return 服务器ip */ public String getServerIp() { return serverIp; } /** * 得到服务器端口 * @return 服务器端口 */ public int getServerPort() { return serverPort; } /** * 发送 * @param netSendParameter 发送参数 */ public void send(NetSendParameter netSendParameter) { if (isConnected) { sendListCacheLock.writeLock().lock(); sendListCache.add(netSendParameter); sendListCacheLock.writeLock().unlock(); unlockSendThread(); } } private void unlockSendThread() { synchronized (lockSendThread) { lockSendThread.notifyAll(); } } @Override public void run() { byte[] bufferReceive = new byte[MAX_FRAME_LENGTH]; DatagramPacket receiveFrame = new DatagramPacket(bufferReceive, MAX_FRAME_LENGTH); while (true) { if (!isConnected) { lockReceiveThread(); } try { int length = inputSteam.read(receiveFrame.getData()); if (length > 0) { receiveFrame.setLength(length); if (FilterFrame.filter(receiveFrame)) { Events.TcpReceiveFrame tcpReceiveFrame = new Events.TcpReceiveFrame(); tcpReceiveFrame.datagramPacket = receiveFrame; RxBus.getInstance().send(tcpReceiveFrame); } } else { exceptionClose(); } } catch (IOException e) { e.printStackTrace(); exceptionClose(); } } } private void lockReceiveThread() { synchronized (lockReceiveThread) { try { lockReceiveThread.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } private void exceptionClose() { if (!tcpSocket.isClosed()) { Log.i(TAG_LOG, "closed1111111111!!!!"); boolean isExceptionClose = isConnected; tcpSocketClose(); if (isExceptionClose) { Events.TcpExceptionClose event = new Events.TcpExceptionClose(); RxBus.getInstance().send(event); } } if (!tcpSocket.isConnected()) { Log.i(TAG_LOG, "disconnect11111111111!!!!"); } } private class SendThread implements Runnable { @Override public void run() { while (true) { if (!isConnected) { clearCache(); sendList.clear(); lockThread(); } copyCache(); if (!sendList.isEmpty()) { sendFrame(); sendList.clear(); } else { lockThread(); } } } private void clearCache() { sendListCacheLock.writeLock().lock(); sendListCache.clear(); sendListCacheLock.writeLock().unlock(); } private void lockThread() { synchronized (lockSendThread) { try { lockSendThread.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } private void copyCache() { sendListCacheLock.readLock().lock(); if (sendListCache.isEmpty()) { sendListCacheLock.readLock().unlock(); } else { sendList.addAll(sendListCache); sendListCacheLock.readLock().unlock(); clearCache(); } } private void sendFrame() { for (NetSendParameter parameter: sendList) { send(parameter); } } private void send(NetSendParameter netSendParameter) { byte[] arr = new byte[MAX_FRAME_LENGTH]; int j = 0; arr[j++] = (byte)(FRAME_HEAD >> 8); arr[j++] = (byte)FRAME_HEAD; arr[j++] = (byte)PROTOCOL_VERSION_CODE; arr[j++] = (byte)(netSendParameter.cmd >> 8); arr[j++] = (byte)netSendParameter.cmd; if (netSendParameter.frameIndex == 0) { int frameIndex = FrameIndex.getInstance().get(); arr[j++] = (byte)(frameIndex >> 8); arr[j++] = (byte)frameIndex; FrameIndex.getInstance().increment(); } else { arr[j++] = (byte) (netSendParameter.frameIndex >> 8); arr[j++] = (byte) netSendParameter.frameIndex; } // 报文长度 arr[j++] = (byte)(netSendParameter.length >> 8); arr[j++] = (byte)netSendParameter.length; int crc = Crc16.calc(netSendParameter.frameBody, 0, netSendParameter.length); arr[j++] = (byte)(crc >> 8); arr[j++] = (byte)crc; // 正文 for (int i = 0; i < netSendParameter.length; i++) { arr[j++] = netSendParameter.frameBody[i]; } try { outputStream.write(arr, 0, j); } catch (IOException e) { e.printStackTrace(); tcpSocketClose(); } } } private class NetAddress { String ip; int port; NetAddress(String ip, int port) { this.ip = ip; this.port = port; } } }
测试代码:
创建连接:
TcpClient.getInstance().makeConnect("115.28.86.171", 21801);
断开连接:
TcpClient.getInstance().close();
NetSendParameter parameter = new NetSendParameter(); parameter.cmd = 3; TcpClient.getInstance().send(parameter);
接收总线消息:
RxBus.getInstance().toObserverable(Events.TcpMakeConnectSuccess.class) .subscribe(t -> Log.e(TAG, "------------------------------------MAKE CONNECT")); RxBus.getInstance().toObserverable(Events.TcpExceptionClose.class) .subscribe(t -> Log.e(TAG, "--------------------------CLOSE"));
作者:jdh99 发表于2017/3/28 12:03:07 原文链接
阅读:299 评论:0 查看评论