/bizsocket-tcp/src/main/java/bizsocket/tcp/SocketConnection.java

https://github.com/typ0520/bizsocket · Java · 356 lines · 278 code · 57 blank · 21 comment · 37 complexity · 874dcf13ec4714392a761547b4cb54a0 MD5 · raw file

  1. package bizsocket.tcp;
  2. import java.io.EOFException;
  3. import java.io.IOException;
  4. import java.net.Socket;
  5. import java.net.SocketException;
  6. import java.util.Collection;
  7. import java.util.Timer;
  8. import java.util.TimerTask;
  9. import java.util.concurrent.CopyOnWriteArrayList;
  10. import bizsocket.logger.Logger;
  11. import bizsocket.logger.LoggerFactory;
  12. import okio.BufferedSink;
  13. import okio.BufferedSource;
  14. import okio.Okio;
  15. /**
  16. * Creates a socket connection to a tcp server.
  17. */
  18. public abstract class SocketConnection implements Connection, ReconnectionManager.ReconnectHandler {
  19. public static final int DEFAULT_HEART_BEAT_INTERVAL = 30000;
  20. /**
  21. * A collection of ConnectionListeners which listen for connection closing
  22. * and reconnection events.
  23. */
  24. protected final Collection<ConnectionListener> connectionListeners = new CopyOnWriteArrayList<ConnectionListener>();
  25. protected final Collection<PacketListener> packetListeners = new CopyOnWriteArrayList<PacketListener>();
  26. protected final PacketFactory packetFactory;
  27. protected final Logger logger = LoggerFactory.getLogger(SocketConnection.class.getSimpleName());
  28. private Socket socket;
  29. private String host;
  30. private int port;
  31. private BufferedSource reader;
  32. private BufferedSink writer;
  33. private PacketWriter packetWriter;
  34. private PacketReader packetReader;
  35. private Timer timer;
  36. private int heartbeat = DEFAULT_HEART_BEAT_INTERVAL;//心跳间隔
  37. private ReconnectionManager reconnectionManager;
  38. private Object lock = new Object();
  39. public SocketConnection() {
  40. this(null,0);
  41. }
  42. public SocketConnection(String host, int port) {
  43. this.host = host;
  44. this.port = port;
  45. packetFactory = createPacketFactory();
  46. }
  47. @Override
  48. public void connect() throws Exception {
  49. disconnect();
  50. logger.debug("connect host: " + host + " port: " + port);
  51. socket = createSocket(host,port);
  52. initConnection();
  53. onSocketConnected();
  54. callConnectionListenerConnected();
  55. }
  56. // @Override
  57. // public void connect(int timeout) {
  58. //
  59. // }
  60. public boolean connectAndStartWatch() {
  61. logger.debug("connectAndStartWatch host: " + host + " port: " + port);
  62. try {
  63. bindReconnectionManager();
  64. connect();
  65. } catch (Exception e) {
  66. e.printStackTrace();
  67. notifyConnectException(e);
  68. return false;
  69. }
  70. return true;
  71. }
  72. @Override
  73. public void disconnect() {
  74. //if (socket != null && !isSocketClosed()) {
  75. if (socket != null) {
  76. logger.debug("disconnect");
  77. try {
  78. if (packetReader != null) {
  79. packetReader.shutdown();
  80. }
  81. } catch (Throwable e) {
  82. //e.printStackTrace();
  83. }
  84. try {
  85. if (packetWriter != null) {
  86. packetWriter.shutdown();
  87. }
  88. } catch (Throwable e) {
  89. //e.printStackTrace();
  90. }
  91. stopHeartBeat();
  92. try {
  93. socket.close();
  94. } catch (Exception e) {
  95. //e.printStackTrace();
  96. }
  97. try {
  98. socket.shutdownInput();
  99. } catch (Exception e) {
  100. //e.printStackTrace();
  101. }
  102. socket = null;
  103. for (ConnectionListener connectionListener : connectionListeners) {
  104. connectionListener.connectionClosed();
  105. }
  106. }
  107. }
  108. @Override
  109. public boolean isConnected() {
  110. return !isSocketClosed();
  111. }
  112. protected abstract PacketFactory createPacketFactory();
  113. public PacketFactory getPacketFactory() {
  114. return packetFactory;
  115. }
  116. public boolean isSocketClosed() {
  117. return socket == null || socket.isClosed() || !socket.isConnected();
  118. }
  119. public BufferedSource getReader() {
  120. return reader;
  121. }
  122. public BufferedSink getWriter() {
  123. return writer;
  124. }
  125. public void addConnectionListener(ConnectionListener connectionListener) {
  126. if (connectionListeners.contains(connectionListener)) {
  127. return;
  128. }
  129. this.connectionListeners.add(connectionListener);
  130. }
  131. public void removeConnectionListener(ConnectionListener connectionListener) {
  132. this.connectionListeners.remove(connectionListener);
  133. }
  134. public void addPacketListener(PacketListener packetListener) {
  135. if (packetListeners.contains(packetListener)) {
  136. return;
  137. }
  138. packetListeners.add(packetListener);
  139. }
  140. public void removePacketListener(PacketListener packetListener) {
  141. packetListeners.remove(packetListener);
  142. }
  143. public void setHostAddress(String host, int port) {
  144. this.host = host;
  145. this.port = port;
  146. }
  147. public void setHeartbeat(int heartbeat) {
  148. this.heartbeat = heartbeat;
  149. }
  150. public void reconnect() {
  151. try {
  152. connect();
  153. } catch (Exception e) {
  154. notifyConnectException(e);
  155. }
  156. }
  157. public void triggerReconnect() {
  158. bindReconnectionManager();
  159. notifyConnectException(new SocketException("触发重连"));
  160. }
  161. public void bindReconnectionManager() {
  162. if (reconnectionManager != null) {
  163. return;
  164. }
  165. reconnectionManager = new ReconnectionManager();
  166. reconnectionManager.bind(this);
  167. reconnectionManager.setReconnectHandler(this);
  168. }
  169. public void unbindReconnectionManager() {
  170. if (reconnectionManager != null) {
  171. reconnectionManager.unbind();
  172. }
  173. reconnectionManager = null;
  174. }
  175. public ReconnectionManager getReconnectionManager() {
  176. return reconnectionManager;
  177. }
  178. protected Socket createSocket(String host, int port) throws Exception {
  179. Socket socket = new Socket(host, port);
  180. socket.setKeepAlive(true);
  181. socket.setTcpNoDelay(true);
  182. return socket;
  183. }
  184. private void notifyConnectException(Exception exception) {
  185. for (ConnectionListener connectionListener : connectionListeners) {
  186. connectionListener.connectionClosedOnError(exception);
  187. }
  188. }
  189. private void initReaderAndWriter() {
  190. try {
  191. reader = Okio.buffer(Okio.source(socket.getInputStream()));
  192. writer = Okio.buffer(Okio.sink(socket.getOutputStream()));
  193. } catch (IOException e) {
  194. e.printStackTrace();
  195. }
  196. }
  197. private void initConnection() {
  198. if (isSocketClosed()) {
  199. return;
  200. }
  201. boolean isFirstInitialization = packetReader == null || packetWriter == null;
  202. initReaderAndWriter();
  203. if (isFirstInitialization) {
  204. this.packetWriter = new PacketWriter(this);
  205. this.packetReader = new PacketReader(this);
  206. }
  207. this.packetWriter.setWriter(writer);
  208. this.packetReader.setReader(reader);
  209. this.packetWriter.startup();
  210. this.packetReader.startup();
  211. }
  212. public void sendPacket(Packet packet) {
  213. if (isSocketClosed()) {
  214. return;
  215. }
  216. packetWriter.sendPacket(packet);
  217. packet.setPacketPool(getPacketFactory().getPacketPool());
  218. }
  219. public void startHeartBeat() {
  220. stopHeartBeat();
  221. synchronized (lock) {
  222. timer = new Timer();
  223. timer.scheduleAtFixedRate(new TimerTask() {
  224. @Override
  225. public void run() {
  226. Packet packet = packetFactory.getHeartBeatPacket();
  227. if (packet == null) {
  228. return;
  229. }
  230. sendPacket(packet);
  231. }
  232. }, 0, heartbeat);
  233. }
  234. }
  235. private void stopHeartBeat() {
  236. synchronized (lock) {
  237. if (null != timer) {
  238. timer.cancel();
  239. }
  240. timer = null;
  241. }
  242. }
  243. public void handleReadWriteError(Exception e) {
  244. if ((e instanceof SocketException) || (e instanceof EOFException)) {
  245. notifyConnectionError(e);
  246. }
  247. }
  248. void notifyConnectionError(Exception exception) {
  249. stopHeartBeat();
  250. packetReader.shutdown();
  251. packetWriter.shutdown();
  252. // Notify connection listeners of the error.
  253. for (ConnectionListener connectionListener : connectionListeners) {
  254. connectionListener.connectionClosedOnError(exception);
  255. }
  256. }
  257. private void callConnectionListenerConnected() {
  258. for (ConnectionListener connectionListener : connectionListeners) {
  259. connectionListener.connected(this);
  260. }
  261. }
  262. protected void onSocketConnected() {
  263. }
  264. /**
  265. * call this method when packet send successful
  266. * @param packet
  267. */
  268. void notifySendSuccessful(Packet packet) {
  269. for (PacketListener packetListener : packetListeners) {
  270. try {
  271. packetListener.onSendSuccessful(packet);
  272. } catch (Throwable e) {
  273. e.printStackTrace();
  274. }
  275. }
  276. if ((packet.getFlags() & Packet.FLAG_AUTO_RECYCLE_ON_SEND_SUCCESS) != 0) {
  277. packet.recycle();
  278. }
  279. }
  280. void handlerReceivedPacket(Packet packet) {
  281. packet.setPacketPool(getPacketFactory().getPacketPool());
  282. for (PacketListener packetListener : packetListeners) {
  283. try {
  284. packetListener.processPacket(packet);
  285. } catch (Throwable e) {
  286. e.printStackTrace();
  287. }
  288. }
  289. }
  290. public void clearWriteQuete() {
  291. if (packetWriter != null) {
  292. packetWriter.clearQueue();
  293. }
  294. }
  295. @Override
  296. public void doReconnect(SocketConnection connection) {
  297. reconnect();
  298. }
  299. }