我们开发过程中如果要实现双机热备份,为了及时获取两台Server之间的连接状态,需要通过”心跳“机制来实现, 以下是 HeartBeatSendService 和 HeartBeatReceiveService的实现,可供参考:
HeartBeatRes.java: 用于作为封装heartbeat message的类
public class HeartBeatRes {
private byte opModeStatus;
private String sysVersion;
public byte getOpModeStatus() {
return opModeStatus;
}
public void setOpModeStatus(byte opModeStatus) {
this.opModeStatus = opModeStatus;
}
public String getSysVersion() {
return sysVersion;
}
public void setSysVersion(String sysVersion) {
this.sysVersion = sysVersion;
}
}
HeartBeatSendService.java: 负责发送heartbeat message, 每秒发送一次
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@Service
public class HeartBeatSendService {
private DatagramSocket datagramSocket ;
private String remoteHost;
private int remotePort;
private static int SEND_MESSAGE_INTERVAL = 1000;
private Gson gson = new GsonBuilder().create();
private SendThread sendThread;
private boolean isStop = false;
private Logger logger = LoggerFactory.getLogger(HeartBeatSendService.class);
public static final byte SYSTEM_OPMODE_STATUS_STANDBY = 0;
public static final byte SYSTEM_OPMODE_STATUS_ACTIVE = 1;
public void start(String remoteHost, int remotePort, int localPort){
try {
isStop = false;
this.stop();
datagramSocket = new DatagramSocket(localPort);
this.remoteHost = remoteHost;
this.remotePort = remotePort;
sendThread = new SendThread();
sendThread.setName("HeartBeat Send Thread");
sendThread.start();
} catch (IOException e) {
e.printStackTrace();
}
}
public void stop() {
if (datagramSocket != null) {
datagramSocket.close();
}
if(sendThread != null){
sendThread.stopThread();
sendThread = null;
}
}
public class SendThread extends Thread {
public void stopThread(){
isStop = true;
// Wake up the thread
synchronized (this) {
this.notify();
}
}
public void run(){
while(!isStop){
try {
Thread.sleep(SEND_MESSAGE_INTERVAL); //控制每秒发一次
} catch (InterruptedException e) {
logger.error(e.getMessage(), e);
}
try {
HeartBeatRes res = new HeartBeatRes();
res.setOpModeStatus(SYSTEM_OPMODE_STATUS_ACTIVE);
res.setSysVersion("1.0");
String message = gson.toJson(res);
byte[] bs = message.getBytes();
DatagramPacket packet = new DatagramPacket(bs, bs.length, InetAddress.getByName(remoteHost), remotePort);
datagramSocket.send(packet);
logger.debug("Send 1+1 heartbeat message:{} length:{} to remote server:{}", new String(bs), String.valueOf(packet.getLength()), remoteHost.toString());
} catch (Throwable e) {
logger.error(e.getMessage(), e);
}
}
}
}
}
HeartBeatReceiveService.java: : 负责接收heartbeat message
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.altai.ac.care.data.exception.NotFoundException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@Service
public class HeartBeatReceiveService{
@Autowired
private ReplicationService repService;
private Logger logger = LoggerFactory.getLogger(HeartBeatReceiveService.class);
private DatagramSocket socket;
private ReceiveThread recvThread;
private Gson gson = new GsonBuilder().create();
private static short SO_TIMEOUT = 3000;
private boolean isStop = false;
private int soTimeout = SO_TIMEOUT;
public void start(int localPort){
try {
isStop = false;
this.stop();
socket = new DatagramSocket(localPort);
socket.setSoTimeout(soTimeout); // 用于设置Socket Timeout, 如果3s没收到message, 认为两台server是断连接了
recvThread = new ReceiveThread();
recvThread.start();
} catch (SocketException e) {
e.printStackTrace();
}
}
public void stop() {
if (socket != null) {
socket.close();
}
if (recvThread != null) {
recvThread.stopThread();
recvThread = null;
}
}
private void parseData(DatagramPacket datagramPacket) throws IOException, NotFoundException, InterruptedException{
byte[] data = datagramPacket.getData();
int length = datagramPacket.getLength();
String jsonData = new String(data, 0, length);
HeartBeatRes heartBeatRes = gson.fromJson(jsonData, HeartBeatRes.class);
// 正常收到数据, 两台server是通的
// 收到的message可根据需要处理
}
public class ReceiveThread extends Thread{
public void stopThread(){
isStop = true;
// Wake up the thread
synchronized (this) {
this.notify();
}
}
public void run() {
while (!isStop) {
try {
byte[] content = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(content, content.length);
if (socket != null) {
socket.receive(datagramPacket);
parseData(datagramPacket);
}
} catch (Throwable e) {
// socket timeout handler
// 可以处理两台server 未连接等情况
}
}
}
}
}
以上代码在源码基础上做了些修改, 没有细测, 理解即可! ^_^