1. Введение
Многие из сегодняшних серверных программ разработаны на основе Java. Для программ Socket, разработанных на Java, если проблема возникает после того, как такая серверная часть подключается к сети, ее необходимо перезапустить вручную, если она зависает посреди ночи. , это все равно очень хлопотно.
Большинство решений заключается в использовании других процессов для защиты серверной программы. Если серверная программа зависает, запустите серверную программу через процесс-демон.
Что делать, если процесс демона зависает? Используйте двойную защиту для повышения стабильности. Защита A отвечает за мониторинг серверной программы, а защита B. Защита B отвечает за мониторинг защиты A. Если есть проблема с любой из сторон, программу можно быстро запустить, чтобы повысить стабильность работы. серверная программа.
Среда выполнения Java отличается от программ, разработанных на таких языках, как C. Программы Java выполняются на JVM. В отличие от языка C, который позволяет напрямую создавать процессы, создание процесса в Java эквивалентно использованию java -jar xxx.jar для запуска программы.
Программа запуска Java не имеет ограничения на один экземпляр, как в C#. Вы можете запустить несколько программ, но не можете запустить более одной. Вы не можете иметь несколько опекунов A для защиты серверной программы. Что делать, если запущено несколько серверных программ?
2. Техническое объяснение
Техническое объяснение здесь довольно грубое. Подробности можно найти в Baidu. Здесь я объясняю только функции.
1. команда jps.
Командный инструмент, поставляемый с JDK, использует jps -l для вывода списка запущенных программ Java и отображения pid и имени программы Java. Действительно только для программ Java. На самом деле вы просматриваете работающую JVM.
2. Использование класса java.nio.channels.FileLock. Это новый класс ввода-вывода Java. Его можно использовать для блокировки файла во время чтения. Когда вы определяете, заблокирован ли файл, вы можете определить, заблокирован ли он. файл заблокирован использованием других программ.
3. ProcessBuilder и процесс
Эти два принципа схожи. Оба они вызывают системные команды для запуска и затем возвращают информацию. Но жесткое кодирование приведет к потере переносимости вашей Java-программы. Вы можете разделить команды в файле конфигурации.
3. Принципы проектирования
Сервер: серверная программа
А: Демон А
Б: Демон Б.
A.lock: блокировка файла демона A.
B.lock: блокировка файла демона B.
-------------------------------------------------- --------------------------------
Шаг 1: Во-первых, не учитывайте сервер, учитывайте только защиту между A и B.
1.А определяет, жив ли Б, и если нет, запускает Б.
2.B определяет, жив ли A, и запускает A, если нет.
3. Во время выполнения A и B обращаются друг к другу, чтобы получить блокировку файлов друг друга. Если они ее получают, это доказывает, что другая сторона не работает, а затем запускает другую сторону.
4. При запуске A получить блокировку файла A.lock. Если она получена, это доказывает, что A не запущен, тогда A запускается, если он не получает блокировку, это доказывает, что A уже запущен, или B получил блокировку при вынесении решения. Если A уже начал игру и нет необходимости начинать игру A снова. Если B получил блокировку при вынесении решения, это не имеет значения, B все равно начнет игру A снова.
5. При запуске B принцип тот же, что и A.
6. Если А зависает во время работы, В определяет, что А повесил трубку, и запускает А. Аналогично.
Шаг 2: Присоединитесь к серверу
1.A используется для защиты B и Сервера, а B используется для защиты A.
2. Принцип тот же, что и в шаге 1, за исключением того, что перед А стоит несколько задач по охране Серера.
3. Когда A запущен, используйте pid процесса, чтобы определить, что сервер завис, а затем запустите сервер.
4. Если и Сервер, и A не работают, B запустит A, а затем A запустит Сервер.
5. Если Сервер и Б не работают, А запускает Сервер и Б.
6. Если оба A и B умрут, защита закончится.
Шаг 3. Используйте «Выключение», чтобы завершить защиту, в противном случае она запустится автоматически после завершения работы сервера.
4. Реализация
1. Реализация GuardA
Скопируйте код кода следующим образом:
общественный класс GuardA {
// GuardA используется для поддержания собственной блокировки
личный файл fileGuardA;
частный FileOutputStream fileOutputStreamGuardA;
частный FileChannel fileChannelGuardA;
частный FileLock fileLockGuardA;
// GuardB используется для обнаружения блокировки B
личный файл fileGuardB;
частный FileOutputStream fileOutputStreamGuardB;
частный FileChannel fileChannelGuardB;
частный FileLock fileLockGuardB;
public GuardA() выдает исключение {
fileGuardA = новый файл (Configure.GUARD_A_LOCK);
если (!fileGuardA.exists()) {
fileGuardA.createNewFile();
}
//Получаем блокировку файла и выходим, если не удается доказать, что GuardA запущен.
fileOutputStreamGuardA = новый FileOutputStream (fileGuardA);
fileChannelGuardA = fileOutputStreamGuardA.getChannel();
fileLockGuardA = fileChannelGuardA.tryLock();
если (fileLockGuardA == ноль) {
Система.выход(0);
}
fileGuardB = новый файл (Configure.GUARD_B_LOCK);
если (!fileGuardB.exists()) {
fileGuardB.createNewFile();
}
fileOutputStreamGuardB = новый FileOutputStream (fileGuardB);
fileChannelGuardB = fileOutputStreamGuardB.getChannel();
}
/**
* Проверьте, существует ли B
*
* @return true B уже существует
*/
общедоступное логическое значение checkGuardB() {
пытаться {
fileLockGuardB = fileChannelGuardB.tryLock();
если (fileLockGuardB == ноль) {
вернуть истину;
} еще {
fileLockGuardB.release();
вернуть ложь;
}
} catch (IOException e) {
Система.выход(0);
// никогда не трогай
вернуть истину;
}
}
}
2. Реализация GuardServer
Скопируйте код кода следующим образом:
общественный класс GuardServer {
частная строка имя_сервера;
public GuardServer (String имя_сервера) {
это.имя_сервера = имя_сервера;
}
public void startServer (String cmd) выдает исключение {
System.out.println("Запустить сервер: " + cmd);
//отдельные команды
// String[] cmds = cmd.split(" ");
// Построитель ProcessBuilder = новый ProcessBuilder(cmds);
//
ProcessBuilder builder = новый ProcessBuilder(new String[]{"/bin/sh","-c",cmd});
//Располагаем вывод серверной программы в /dev/tty
builder.redirectOutput(новый файл("/dev/tty"));
builder.redirectError(новый файл("/dev/tty"));
builder.start(); // выдает IOException
Thread.sleep(10000);
}
/**
* Проверьте, существует ли услуга
*
* @return Возвращает pid настроенной Java-программы.
* @return pid >0 возвращает pid <=0, что означает, что указанная Java-программа не запущена.
* **/
public int checkServer() выдает исключение {
интервал пид = -1;
Процесс процесс = ноль;
Читатель BufferedReader = null;
процесс = Runtime.getRuntime().exec("jps -l");
читатель = новый BufferedReader (новый InputStreamReader (process.getInputStream ()));
Струнная линия;
while ((line = readLine()) != null) {
String[] strings = line.split("//s{1,}");
если (строки. длина <2)
продолжать;
if (strings[1].contains(servername)) {
pid = Integer.parseInt(strings[0]);
перерыв;
}
}
читатель.закрыть();
процесс.уничтожить();
вернуть идентификатор;
}
}
3. Реализация GuardAMain
Скопируйте код кода следующим образом:
общественный класс GuardAMain {
public static void main(String[] args) выдает исключение {
GuardA GuardA = новый GuardA();
Настройка configure = новая настройка();
Сервер GuardServer = новый GuardServer(configure.getServername());
в то время как (истина) {
// Запускаем GuardB, если GuardB не запущен
if (!guardA.checkGuardB()) {
System.out.println("Запустить GuardB....");
Runtime.getRuntime().exec(configure.getStartguardb());
}
// Проверяем выживаемость сервера
если (server.checkServer() <= 0) {
логическое значение isServerDown = true;
// проверка поездки
для (int я = 0; я <3; я++) {
// Если сервис жив
если (server.checkServer() > 0) {
isServerDown = ложь;
перерыв;
}
}
если (иссервердаун)
server.startServer(configure.getStartserver());
}
Thread.sleep(configure.getInterval());
}
}
}
4. Осуществление отключения
Скопируйте код кода следующим образом:
общественный класс ShutDown {
public static void main(String[] args) выдает исключение {
Настройка configure = новая настройка();
System.out.println("Защита отключения..");
для (int я = 0; я <3; я++) {
Процесс p = Runtime.getRuntime().exec("jps -l");
Читатель BufferedReader = новый BufferedReader (новый InputStreamReader (p.getInputStream ()));
Струнная линия;
while ((line = readLine()) != null) {
if (line.toLowerCase().contains("Guard".toLowerCase()))) {
String[] strings = line.split("//s{1,}");
int pid = Integer.parseInt(strings[0]);
Runtime.getRuntime().exec(configure.getKillcmd() + " " + pid);
}
}
п.waitFor();
читатель.закрыть();
п.уничтожить();
Thread.sleep(2000);
}
System.out.println("Защита отключена");
}
}
5. GuardB похож на GuardA.
5. Загрузите и используйте
Папка проекта: Guard_demo
Адрес загрузки: http://pan.baidu.com/s/1bn1Y6BX
Если у вас есть какие-либо вопросы или предложения, пожалуйста, свяжитесь со мной