前言
项目需要和第三方厂商的服务需要用TCP协议通讯,考虑到彼此双方可能都会有断网重连、宕机重启的情况,需要保证 发生上述情况后,服务之间能够自动实现重新通信。研究测试之后整理如下代码实现。因为发现客户端重启后,对于服务端来说原来的客户端和服务端进程进程已经关闭,启动又和服务端新开了一个进程。所以实现原理就可以通过服务端向客户端群发实现,断开重新连接通讯。
代码
tcp服务端代码
import java.io.*; import java.net.ServerSocket; import java.net.Socket; public class HttpSocketServer { public static void main(String[] args) { try { ServerSocket server=new ServerSocket(9020); while (true){ Socket client=server.accept(); client.setKeepAlive(true); client.setOOBInline(true); System.out.println("进入了1个客户机连接:"+client.getRemoteSocketAddress().toString()); ServerThread st = new ServerThread(client); st.start(); } } catch (IOException e) { e.printStackTrace(); } } }
ServerThread 线程类
import java.io.*; import java.net.Socket; /** * 客户机 线程 ——自动执行run * @author Lenovo */ public class ServerThread extends Thread{ private Socket client; /** * 方法描述: 用有参构造 接收主函数那边传来的 客户机 */ public ServerThread(Socket client) { this.client=client; } @Override public void run() { try { processSocket();//调用你想执行的 使线程启动时在run方法开始执行 } catch (IOException e) { e.printStackTrace(); } } /** * 调用以上方法 */ public void processSocket() throws IOException { //加入集合 便于服务器群发 TcpTool.addSocket(client); }
TcpTool 消息群发工具类
import java.io.IOException; import java.io.OutputStream; import java.net.Socket; import java.util.ArrayList; import java.util.List; /** * 聊天工具类 * @author tarzan */ public class TcpTool { private static List<Socket> clientList=new ArrayList<Socket>(); /** * 便于 验证成功后 加入客户机 * @param socket */ public static void addSocket(Socket socket) { clientList.add(socket); } /** * 群发=遍历list中的all元素, 对每个元素 写出 * @param msg * @throws IOException */ public static void sendAll(String msg){ for (int i = 0; i <clientList.size(); i++) { Socket client = clientList.get(i); if(clientIsClose(client)){ delSocket(client); i--; continue; } try { OutputStream ops = client.getOutputStream(); ops.write((msg+"\r\n").getBytes()); ops.flush(); } catch (IOException e) { e.printStackTrace(); } } } /** * 判断是否断开连接,断开返回true,没有返回false * @param socket * @return */ public static Boolean clientIsClose(Socket socket){ try{ //发送1个字节的紧急数据,默认情况下,服务器端没有开启紧急数据处理,不影响正常通信 socket.sendUrgentData(0xFF); // 发送一个数据包, 如果通信正常就不会报错. 没有报错说明没有关闭., 返回false return false; }catch(Exception se){ return true; } } /** * 下线时删除 * @param socket */ public static void delSocket(Socket socket){ clientList.remove(socket); } }
Tcp客户端代码
import org.springblade.core.tool.utils.StringUtil; import java.io.*; import java.net.Socket; /** * @author tarzan */ public class HttpSocketClient { public static void main(String[] args) throws IOException { Socket client=new Socket("127.0.0.1",9020); client.setKeepAlive(true); client.setOOBInline(true); while (true) { try { if (!clientIsClose(client)) { InputStream is=client.getInputStream(); BufferedReader reader=new BufferedReader(new InputStreamReader(is)); String text=reader.readLine(); if(StringUtil.isNotBlank(text)){ System.out.println("来自服务端的消息:"+text); } }else{ try { //断开5秒后重新连接 Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } client=new Socket("127.0.0.1",9020); } } catch (IOException e) { e.printStackTrace(); } } } public static Boolean clientIsClose(Socket socket){ try{ //发送1个字节的紧急数据,默认情况下,服务器端没有开启紧急数据处理,不影响正常通信 socket.sendUrgentData(0xFF); // 发送一个数据包, 如果通信正常就不会报错. 没有报错说明没有关闭., 返回false return false; }catch(Exception se){ return true; } }
运行一个服务端,启动多个客户端进行测试。
控制台输出
编辑
以上只是实现的最简单的demo,服务端,因为服务端和客户端都需要不断监听彼此通信,发送消息时候,需要另起一个线程,调用TcpTool工具类想客户端群发消息。