实现JavaWeb服务的双机热备操作,这里通过WebSocket方式,设置每个一段时间发送TCP报文,通过报文接收的结果来限制主从服务的运行。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import javax.annotation.Resource;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSONObject;
/**
* @author 作者 : xxxxx
* @version 创建时间:2021年8月22日 上午9:18:24
* 心跳检测-----主服务器发送send服务
*/
public class HeartSend implements ServletContextListener {
private SocketThread socketThread;
public void contextDestroyed(ServletContextEvent arg0) {
}
@Override
public void contextInitialized(ServletContextEvent arg0) {
if(null==socketThread)
{
//新建线程类
socketThread=new SocketThread(null);
//启动线程
socketThread.start();
}
}
}
class SocketThread extends Thread {
private ServerSocket serverSocket = null;
public SocketThread(ServerSocket serverScoket){
try {
if(null == serverSocket){
this.serverSocket = new ServerSocket(9998);
}
} catch (Exception e) {
System.out.println("SocketThread创建socket服务出错");
e.printStackTrace();
}
}
public void run(){
try {
if(serverSocket==null){
return;
}else if(serverSocket.isClosed()){
return;
}
Socket socket = serverSocket.accept();
if(null != socket && !socket.isClosed()){
//处理接受的数据
Thread t1 = new Thread(new SocketOperate(socket));
t1.start();
}else{
return;
}
}catch (Exception e) {
System.out.println("SocketThread创建socket服务出错");
e.printStackTrace();
}
}
public void closeSocketServer(){
try {
if(null!=serverSocket && !serverSocket.isClosed())
{
serverSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
class SocketOperate implements Runnable {
private Socket socket;
public SocketOperate(Socket socket) throws IOException {
this.socket = socket;
}
@Override
public void run() {
try {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
while(true){
Thread.sleep(5000); // 每5秒钟发送一次心跳检测信息
JSONObject jobject = new JSONObject();
jobject.put("type", "heart");
jobject.put("message", "主服务器发送心跳检测信息!");
oos.writeObject(jobject);
oos.flush();
}
} catch (Exception e) {
e.printStackTrace();
} finally{
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
通过启动一个线程方式实现socket方式每个5秒钟发送一次心跳信息,供监听端接收
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.ibatis.javassist.bytecode.stackmap.TypeData.ClassName;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSONObject;
/**
* @author 作者 : xxxxx
* @version 创建时间:2021年8月22日 下午3:47:33
* 心跳检测 ----从服务器监听listen服务
*/
public class HeartListen implements ServletContextListener {
public static String heartStatus = "error"; //从服务器是否能够发送告警标识(error不能发送,success能够发送)
private static Socket socket;
public static boolean connect_state = false;
private static SocketThread1 socketThread;
private static Properties prop = PropertiesUtils.getProperties("db.properties");
public static String HostHeardIp = prop.getProperty("HostHeardIp");//获取主服务器地址
@Override
public void contextDestroyed(ServletContextEvent arg0) {
}
@Override
public void contextInitialized(ServletContextEvent arg0) {
while(!connect_state){
connect(); // 连接主程序
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//连接主服务器地址
private static void connect(){
try {
//新建线程类
socketThread=new SocketThread1(socket);
//启动线程
socketThread.start();
} catch (Exception e) {
e.printStackTrace();
connect_state = false;
}
}
//实现服务连接断掉之后的重连接
public static void reconnect(){
while(!connect_state){
connect();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class SocketThread1 extends Thread
{
private Socket socket;
public SocketThread1(Socket socket){
this.socket = socket;
}
public void run(){
try {
socket = new Socket(HeartListen.HostHeardIp,9998);
new Thread(new ClientListen(socket)).start(); // 从服务器接收信息
new Thread(new ClientHeart(socket)).start(); // 检测主从服务器连接状态
HeartListen.connect_state = true;
}catch (Exception e) {
//设置告警的全局变量
HeartListen.heartStatus = "success";
System.out.println("SocketThread创建socket服务出错");
HeartListen.connect_state = false;
}
}
}
//从服务器接收信息
class ClientListen implements Runnable{
private Socket socket;
ClientListen(Socket socket){
this.socket = socket;
}
@Override
public void run() {
//接收发送过来的信息
try {
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
//判断接收过来的信息,做后面的操作
while(true){
Object obj = ois.readObject();
//判断接收信息,做后续操作
if(obj == null || "".equals(obj)){ // 将配置文件中的状态置为1 (从服务器定时为1才发送定时信息)
//设置告警的全局变量
HeartListen.heartStatus = "success";
System.out.println("主程序发送心跳--失败--");
}else{ // 将配置文件中的状态值为0
//设置告警的全局变量
HeartListen.heartStatus = "error";
System.out.println("主程序发送心跳--成功--");
}
}
} catch (Exception e) {
//设置告警的全局变量
HeartListen.heartStatus = "success";
System.out.println("主程序发送心跳--失败---");
e.printStackTrace();
}finally{
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//从服务器发送心跳检测信息(目的:当主从服务器断开连接后,尝试重连)
class ClientHeart implements Runnable{
private Socket socket;
ClientHeart(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
while(true){
JSONObject object = new JSONObject();
object.put("type", "heart");
object.put("message", "判断主从服务器连接心跳检测");
oos.writeObject(object);
oos.flush();
}
} catch (IOException e) {
e.printStackTrace();
try {
socket.close();
HeartListen.connect_state = false;
HeartListen.reconnect();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
我这边通过接收端中全局参数HeartStatus变量来控制从服务中各个功能的运行,HostHeardIp变量是从配置文件中获取安装主服务的服务器IP地址。ClientHeart类用来判断主程序是否需要重连操作。
在src\main\webapp\WEB-INF此目录下的web.xml文件中配置发送类和接收类监听:
<listener>
<listener-class>cn.com.test.heart.HeartListenlistener-class>
listener>
<listener>
<listener-class>cn.com.test.heart.HeartSendlistener-class>
listener>
(参考地址:https://blog.csdn.net/u013510614/article/details/109851112?utm_source=app)