It is a monitoring program that I have used in order to simplify server startup and kill.
There is a monitoring function if there is an abnormality in one of the servers, it is possible to restart from killing all servers.
There is a schedule function, it is possible to shut down or restart the server to the required time.
View attachment A3 Monitor.zip
Is created using the AutoHotkey, is a Korean environment. Please use by modifying the source if needed.
The source code includes a scheduling function of the ZS for event. In my memory, perhaps this feature was not tested.
A3 Monitor.ahk
SvrInfo.ini
There is a monitoring function if there is an abnormality in one of the servers, it is possible to restart from killing all servers.
There is a schedule function, it is possible to shut down or restart the server to the required time.
View attachment A3 Monitor.zip
Is created using the AutoHotkey, is a Korean environment. Please use by modifying the source if needed.
The source code includes a scheduling function of the ZS for event. In my memory, perhaps this feature was not tested.
A3 Monitor.ahk
Code:
#SingleInstance Force
#NoTrayIcon
#NoEnv
FormatTime, _sDays, A_Now, yyyyMMdd
FormatTime, _eDays, A_Now, yyyyMMdd
_sHour := ""
_eHour := ""
_sMin := ""
_eMin := ""
_eStart := ""
_eEnd := ""
_PID := ""
;gui start
Gui, Font,, Segoe UI
Gui, Add, GroupBox, x5 y5 w340 h55 cBlack, Server Scheduler
Gui, Font, s11 Bold
Gui, Add, Edit, xp+5 yp+20 h28 w48 Number vSetHour0
Gui, Add, UpDown, vSetHour Wrap Range0-23, 0
Gui, Font, s19
Gui, Add, Text, x+5 yp-7, :
Gui, Font, s11
Gui, Add, Edit, x+5 yp+7 h28 w48 Number vSetMin0
Gui, Add, UpDown, vSetMin Wrap Range0-59, 0
Gui, Font, s9 Normal
Gui, Add, CheckBox, x+20 yp-6 vsOp1 gOper, 서버종료
Gui, Add, CheckBox, xp y+4 vsOp2 gOper, 서버재시작
Gui, Font, s20 Normal
Gui, Add, Text, x+40 yp-22 vScheInfo cBLUE, OFF
Gui, Font, s9 Normal
Gui, Add, GroupBox, x5 y+10 w340 h85 cBlack, Event ZS Scheduler
Gui, Font, s9 Normal
Gui, Add, CheckBox, xp+5 yp+18 vsOp3 geOper, 시작
Gui, Font, s11 Bold
Gui, Add, Edit, xp y+2 h28 w48 Number vSetESHour0
Gui, Add, UpDown, vSetESHour Wrap Range0-23, 0
Gui, Font, s19
Gui, Add, Text, x+5 yp-7, :
Gui, Font, s11
Gui, Add, Edit, x+5 yp+7 h28 w48 Number vSetESMin0
Gui, Add, UpDown, vSetESMin Wrap Range0-59, 0
Gui, Font, s9 Normal
Gui, Add, CheckBox, x+15 yp-17 vsOp4 geOper, 종료
Gui, Font, s11 Bold
Gui, Add, Edit, xp y+2 h28 w48 Number vSetEEHour0
Gui, Add, UpDown, vSetEEHour Wrap Range0-23, 0
Gui, Font, s19
Gui, Add, Text, x+5 yp-7, :
Gui, Font, s11
Gui, Add, Edit, x+5 yp+7 h28 w48 Number vSetEEMin0
Gui, Add, UpDown, vSetEEMin Wrap Range0-59, 0
Gui, Font, s9 Normal
Gui, Add, CheckBox, x+20 yp-17 vsOp5 geOper, 반복
Gui, Font, s11 Bold
Gui, Add, Edit, xp y+2 h28 w48 Number vSetRepeat
Gui, Font, s16 normal
Gui, Add, Text, x+2 yp-2, h
Gui, Font, s9 Normal
Gui, Add, Text, xs+5 y+3 w125 vNextStart cBLUE
Gui, Add, Text, x+3 yp w125 vNextEnd cRed
Gui, Add, Text, x+3 yp w75 vzsPID cBlack
GuiControl, Disable, sOp4
GuiControl, Disable, sOp5
;Gui, Font, s20 Normal
;Gui, Add, Text, x+40 yp-22 veScheInfo cBLUE, OFF
Gui, Font, s9 Normal
Gui, Add, GroupBox, x5 y+10 w340 h100 cBlack, Serverlist
Gui, Font, s8
Gui, Add, Edit, xs+5 yp+20 w329 h73 vSvrlist ReadOnly -Wrap
Gui, Add, Text, x5 y+18 vInfo w265 cRED Center
Gui, Add, Button, x+5 yp-5 w70 h30 gKillServer, 서버 종료
Gui, Add, Button, xp y+5 w70 h30 gStartServer, 서버 시작
Gui, Add, Button, xp y+5 w70 h30 vBT_M gTG_Monitor, 감시 시작
Gui, Add, Edit, x5 yp-44 w265 h73 vSvrLog ReadOnly
Gui, Add, GroupBox, x5 y+10 w340 h48 cBlack, Update Server
Gui, Add, Button, xp+5 yp+18 w330 h24 vBT_U gTG_Update
Gui, Show, w350, A3 Monitor ⓒ 2013 by prologos
;ini read
IniRead, UpdatePath, SvrInfo.ini, UpdateInfo, UpdatePath
If (!UpdatePath OR UpdatePath = "ERROR")
{
GuiControl,, BT_U, 설정파일에 설정값 없음
GuiControl, -g, BT_U
}
else
{
IfExist, %UpdatePath%
{
GuiControl,, BT_U, [ ON ] 업데이트 가능
Update_Tg := True
}
else IfExist, %UpdatePath%_off
{
GuiControl,, BT_U, [ OFF ] 업데이트 불가능
Update_Tg := False
}
else
{
GuiControl,, BT_U, 업데이트 폴더 지정이 잘못됨
GuiControl, -g, BT_U
}
}
IniRead, ServerMax, SvrInfo.ini, SvrInfo, ServerMax
If (!ServerMax OR ServerMax = "ERROR")
ServerMax := 0
IniRead, WinWaitSec, SvrInfo.ini, SvrInfo, WinWaitSec, 30
IniRead, Interval, SvrInfo.ini, SvrInfo, Interval, 60
Interval := Interval * 1000 ;sec을 ms로 변환
Svrlist := ""
Loop, % ServerMax + 1
{
IDX := A_Index - 1
IniRead, SvrPath%IDX%, SvrInfo.ini, SvrInfo, SvrPath%IDX%
If (!SvrPath%IDX% OR SvrPath%IDX% = "ERROR")
SvrPath%IDX% := ""
Else
{
StringSplit, tmp, SvrPath%IDX%, `,
Loop, 5 ;서버 Path를 제외하고 나머지 변수들은 공백제거
{
If (A_Index > 1)
StringReplace, tmp%A_Index%, tmp%A_Index%, %A_SPACE%,, All
}
SvrPath%IDX% := tmp1
WinSize%IDX% := tmp2
WinX%IDX% := tmp3
WinY%IDX% := tmp4
WinClick%IDX% := tmp5
tmp := ""
Loop, % 2 - StrLen(IDX)
tmp .= "0"
Svrlist .= "[" . tmp . IDX . "] " . SvrPath%IDX% . "`n"
;풀 패스(SvrPath%IDX%)를 디렉토리(SvrDir%IDX%)와 파일명(SvrName%IDX%)으로 분리
SplitPath, SvrPath%IDX%, SvrName%IDX%, SvrDir%IDX%
}
}
StringReplace, Svrlist, Svrlist, [00], [eZS]
GuiControl,, Svrlist, % SubStr(Svrlist, 1, StrLen(Svrlist)-1)
Return
;이벤트서버
eOper:
Gui, Submit, NoHide
if (A_GuiControl = "sOp3")
{
if (sOp3 = 1)
{
;시작시간 셋팅
FormatTime, _sDays, A_Now, yyyyMMdd
SetESHour := "0" . SetESHour
StringRight, _sHour, SetESHour, 2
SetESMin := "0" . SetESMin
StringRight, _sMin, SetESMin, 2
FormatTime, _eStart, % _sDays . _sHour . _sMin, yyyyMMddHHmm
GuiControl, Enable, sOp4
GuiControl,, NextStart, % "다음시작: " . Substr(_eStart, 5, 2) . "-" . Substr(_eStart, 7, 2) . " " . Substr(_eStart, 9, 2) . ":" . Substr(_eStart, 11, 2)
GuiControl, +ReadOnly, SetESHour0
GuiControl, +ReadOnly, SetESMin0
GuiControl, Disable, SetESHour
GuiControl, Disable, SetESMin
;ZS시작 타이머 시작: 1분마다 체크
SetTimer, EventZS_Start, 60000
}
else
{
GuiControl,, sOp4, 0
GuiControl,, sOp5, 0
GuiControl, Disable, sOp4
GuiControl, Disable, sOp5
;시작 컨트롤 원복
GuiControl,, NextStart
GuiControl, -ReadOnly, SetESHour0
GuiControl, -ReadOnly, SetESMin0
GuiControl, Enable, SetESHour
GuiControl, Enable, SetESMin
;타이머 끄기
SetTimer, EventZS_Start, Off
;종료 컨트롤 원복
GuiControl,, NextEnd
GuiControl, -ReadOnly, SetEEHour0
GuiControl, -ReadOnly, SetEEMin0
GuiControl, Enable, SetEEHour
GuiControl, Enable, SetEEMin
;반복 컨트롤 원복
GuiControl, -ReadOnly, SetRepeat
}
}
else if (A_GuiControl = "sOp4")
{
if (sOp4 = 1)
{
;종료시간 셋팅
FormatTime, _eDays, A_Now, yyyyMMdd
SetEEHour := "0" . SetEEHour
StringRight, _eHour, SetEEHour, 2
SetEEMin := "0" . SetEEMin
StringRight, _eMin, SetEEMin, 2
FormatTime, _eEnd, % _eDays . _eHour . _eMin, yyyyMMddHHmm
;종료 시간이 시작 시간보다 작은경우는 다음날로 간주
if (_eStart >= _eEnd)
{
EnvAdd, _eEnd, 24, hours
FormatTime, _eEnd, %_eEnd%, yyyyMMddHHmm
}
GuiControl, Enable, sOp5
GuiControl,, NextEnd, % "다음종료: " . Substr(_eEnd, 5, 2) . "-" . Substr(_eEnd, 7, 2) . " " . Substr(_eEnd, 9, 2) . ":" . Substr(_eEnd, 11, 2)
GuiControl, +ReadOnly, SetEEHour0
GuiControl, +ReadOnly, SetEEMin0
GuiControl, Disable, SetEEHour
GuiControl, Disable, SetEEMin
;ZS시작 타이머 시작: 1분마다 체크
SetTimer, EventZS_End, 60000
}
else
{
GuiControl,, sOp5, 0
GuiControl, Disable, sOp5
GuiControl,, NextEnd
GuiControl, -ReadOnly, SetEEHour0
GuiControl, -ReadOnly, SetEEMin0
GuiControl, Enable, SetEEHour
GuiControl, Enable, SetEEMin
;타이머 끄기
SetTimer, EventZS_End, Off
}
}
else if (A_GuiControl = "sOp5")
{
if (sOp5 = 1)
{
GuiControl, +ReadOnly, SetRepeat
}
else
{
GuiControl, -ReadOnly, SetRepeat
}
}
Return
;이벤트 ZS 종료
EventZS_End:
Gui, Submit, NoHide
FormatTime, CurrentTime, %A_Now%, yyyyMMddHHmm
if (CurrentTime = _eEnd)
{
;eZS종료 코드 넣을곳
RunWait, %ComSpec% /C TASKKILL /F /PID %_PID%,, Hide
GuiControl,, zsPID
if (sOp5 = 1)
{
;반복 체크되어 있을때 다음 시작 시간 계산
EnvAdd, _eEnd, SetRepeat, hours
FormatTime, _eEnd, %_eEnd%, yyyyMMddHHmm
GuiControl,, NextEnd, % "다음종료: " . Substr(_eEnd, 5, 2) . "-" . Substr(_eEnd, 7, 2) . " " . Substr(_eEnd, 9, 2) . ":" . Substr(_eEnd, 11, 2)
}
else
{
GuiControl,, NextEnd
;타이머 끄기
SetTimer, EventZS_End, Off
}
}
Return
;이벤트 ZS 시작
EventZS_Start:
Gui, Submit, NoHide
FormatTime, CurrentTime, %A_Now%, yyyyMMddHHmm
if (CurrentTime = _eStart)
{
;eZS시작 코드 넣을곳 pid: zsPID
Run, "%SvrPath0%", %SvrDir0%, UseErrorLevel, _PID
WinWait, ahk_pid %_PID%,, %WinWaitSec%
If ErrorLevel
Goto TimedOut
Sleep 200
;이벤트용 ZS의 PID표시
GuiControl,, zsPID, %_PID%
;반복 체크되어 있을때 다음 시작 시간 계산
if (sOp5 = 1)
{
EnvAdd, _eStart, SetRepeat, hours
FormatTime, _eStart, %_eStart%, yyyyMMddHHmm
GuiControl,, NextStart, % "다음시작: " . Substr(_eStart, 5, 2) . "-" . Substr(_eStart, 7, 2) . " " . Substr(_eStart, 9, 2) . ":" . Substr(_eStart, 11, 2)
}
else
{
GuiControl,, NextStart
;타이머 끄기
SetTimer, EventZS_Start, Off
}
}
Return
;예약작업
Oper:
Gui, Submit, NoHide
if (A_GuiControl = "sOp1")
{
GuiControl,, sOp2, 0
if (sOp1 = 1)
GuiControl, Disable, sOp2
else
GuiControl, Enable, sOp2
}
else if (A_GuiControl = "sOp2")
{
GuiControl,, sOp1, 0
if (sOp2 = 1)
GuiControl, Disable, sOp1
else
GuiControl, Enable, sOp1
}
if (sOp1 = 1 or sOp2 = 1)
{
GuiControl,, ScheInfo, ON
GuiControl, +ReadOnly, SetHour0
GuiControl, +ReadOnly, SetMin0
GuiControl, Disable, SetHour
GuiControl, Disable, SetMin
if (sOp1 = 1)
SetTimer, ScheKill, 60000
else if (sOp2 = 1)
SetTimer, ScheRestart, 60000
}
else
{
GuiControl,, ScheInfo, OFF
GuiControl, -ReadOnly, SetHour0
GuiControl, -ReadOnly, SetMin0
GuiControl, Enable, SetHour
GuiControl, Enable, SetMin
SetTimer, ScheKill, Off
SetTimer, ScheRestart, Off
}
;msgbox, %A_GuiControl% - %SetHour%:%SetMin% %sOp1% - %sOp2%
Return
;스케줄 - 서버종료
ScheKill:
Gui, Submit, NoHide
if (SetHour = A_Hour and SetMin = A_Min)
{
GuiControl,, sOp1, 0
GuiControl,, sOp2, 0
GuiControl, Enable, sOp1
GuiControl, Enable, sOp2
GoSub Oper
;모니터링 상태이면 모니터링 끄기
if (Monitoring_Tg)
GoSub TG_Monitor
;업데이트 가능상태이면 불가능으로 만들기
if (Update_Tg)
{
GoSub TG_Update
;FileMove, %UpdatePath%vn.ini, %UpdatePath%vn_off.ini, 1
;GuiControl,, BT_U, [ OFF ] 업데이트 불가능
;Update_Tg := Not Update_Tg
}
Step := "Schedule"
Step := "KILL " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " / Cause [" . Step . "]"
Err(Step)
GoSub KillServer
}
Return
;스케줄 - 서버 재시작
ScheRestart:
Gui, Submit, NoHide
if (SetHour = A_Hour and SetMin = A_Min)
{
;업데이트 서버 중단
if (Update_Tg)
{
GoSub TG_Update
}
GuiControl,, sOp1, 0
GuiControl,, sOp2, 0
GuiControl, Enable, sOp1
GuiControl, Enable, sOp2
GoSub Oper
Step := "Schedule"
;모니터링 상태이면 모니터링 끄기고 작업후 다시 켜기
if (Monitoring_Tg)
{
GoSub TG_Monitor
GoSub ServerRestart
GoSub TG_Monitor
}
else
GoSub ServerRestart
;업데이트 서버 재개
if (!Update_Tg)
{
GoSub TG_Update
}
}
Return
;업데이트 서버 설정부분
TG_Update:
Update_Tg := Not Update_Tg
if (Update_Tg)
{
FileMoveDir, %UpdatePath%_off, %UpdatePath%, R
GuiControl,, BT_U, [ ON ] 업데이트 가능
}
else
{
FileMoveDir, %UpdatePath%, %UpdatePath%_off, R
GuiControl,, BT_U, [ OFF ] 업데이트 불가능
}
Return
KillServer:
;GuiControl,, Info, 서버 종료중...
Loop, %ServerMax%
{
Num := ServerMax + 1 - A_Index
SvrName := SvrName%Num%
If (SvrName)
{
tmp := ""
Loop, % 2 - StrLen(Num)
tmp .= "0"
GuiControl,, Info, [%tmp%%Num%] 서버 종료중...
RunWait, %ComSpec% /C TASKKILL /F /IM %SvrName%,, Hide
}
}
GuiControl,, Info, 서버 종료 완료
Return
StartServer:
GuiControl,, Info, 서버 시작하는중...
;BlockInput, MouseMove
Loop, %ServerMax%
{
Step := A_Index
SvrPath := SvrPath%A_Index%
SvrDir := SvrDir%A_Index%
If (SvrPath)
{
Run, "%SvrPath%", %SvrDir%, UseErrorLevel, PID
WinWait, ahk_pid %PID%,, %WinWaitSec%
If ErrorLevel
Goto TimedOut
Sleep 200
;설정에따라 클릭이 필요하면 처리함
If (WinClick%A_Index%)
{
If (WinClick%A_Index% = 3) ;GM Shouts by ChrissDeGrece의 경우
{
CountWhile := 0
While 1
{
ControlGetFocus, TBcheck, ahk_pid %PID%
if (TBcheck = "ListBox1")
ControlClick, Button4, ahk_pid %PID%,, LEFT, 1
else if (TBcheck = "Button1")
ControlClick, Button1, ahk_pid %PID%,, LEFT, 1
else if (TBcheck = "Button4")
Break
CountWhile++
If (CountWhile > 50)
Goto TimedOut
}
}
else if (WinClick%A_Index% = 2) ;GM Shouts by prologos의 경우
{
TBcheck := 1
CountWhile := 0
While (TBcheck)
{
ControlGet, TBcheck, Enabled,, Button4, ahk_pid %PID%
ControlClick, Button4, ahk_pid %PID%,, LEFT, 2
CountWhile++
If (CountWhile > 50)
Goto TimedOut
}
}
else ;ODBC 설정의 경우
{
TBname1 := "TButton4"
TBname2 := "TButton5"
TBname3 := "TButton2"
Loop, 3
{
TBname := TBname%A_Index%
TBcheck := 1
CountWhile := 0
While (TBcheck)
{
ControlGet, TBcheck, Enabled,, %TBname%, ahk_pid %PID%
ControlClick, %TBname%, ahk_pid %PID%,, LEFT, 2
CountWhile++
If (CountWhile > 50)
Goto TimedOut
}
}
While (!TBcheck) ;리스트박스에 "[OK] Listening" 메시지 뜰때까지 대기
{
ControlGet, TBcheck, List,, TColorListBox1, ahk_pid %PID%
}
}
}
;설정에따라 창을 최소화하거나 지정된 위치로 이동시킴
If (!WinSize%A_Index%)
WinMinimize, ahk_pid %PID%
else
WinMove, ahk_pid %PID%,, WinX%A_Index%, WinY%A_Index%
Sleep 500 ;서버하나 실행후 잠시 텀두기
}
}
;BlockInput, MouseMoveOff
GuiControl,, Info, 서버 시작 완료
Return
TimedOut:
;BlockInput, MouseMoveOff
GuiControl,, Info, 서버 시작 오류
Loop, % 2 - StrLen(Step)
Step := "0" . Step
Step := "[" . Step . "] / " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec
Err("TIMEOUT " . Step)
Return
TG_Monitor:
Monitoring_Tg := Not Monitoring_Tg
MonitorInfo(Monitoring_Tg)
If (Monitoring_Tg)
SetTimer, Monitoring, %Interval%
Else
SetTimer, Monitoring, Off
Return
Monitoring:
MonitorInfo(Monitoring_Tg)
If (Monitoring_Tg)
{
Loop, %ServerMax%
{
SvrName := SvrName%A_Index%
If (SvrName)
{
Step := A_Index
Process, Exist, %SvrName%
If (ErrorLevel = 0)
Goto ServerRestart
}
}
}
Else
SetTimer, Monitoring, Off
Return
ServerRestart:
Loop, % 2 - StrLen(Step)
Step := "0" . Step
Step := "RESTART " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " / Cause [" . Step . "]"
Err(Step)
;업데이트서버 상태 반전
GoSub TG_Update
;서버 재시작
GoSub KillServer
GoSub StartServer
;업데이트서버 상태 원복
GoSub TG_Update
Return
GuiClose:
GuiEscape:
ExitApp
Err(msg) {
GuiControlGet, tmp,, SvrLog
tmp := msg . "`n" . tmp
GuiControl,, SvrLog, %tmp%
}
MonitorInfo(Toggle) {
If (Toggle)
{
GuiControl,, Info, 모니터링중...
GuiControl,, BT_M, 감시 종료
}
else
{
GuiControl,, Info, 모니터링 종료
GuiControl,, BT_M, 감시 시작
}
}
SvrInfo.ini
Code:
*************************************************************************************************
* ServerMax : SvrPath의 마지막 번호 *
* SvrPath? : Full Path *
* 0-Minimize | 1-WinMove *
* X좌표(WinMove일경우) *
* Y좌표 *
* 0-클릭없음 | 1-ODBC | 2-GM Shouts by prologos | 3-GM Shouts by ChrissDeGrece *
* SvrPath0 : 이벤트용 존서버 *
* Interval : 서버 모니터링 인터벌(초) *
* WinWaitSec : 서버 실행시 창의 활성화시까지 대기시간(초) *
* UpdatePath : 업데이트 파일들이 있는 폴더. 마지막 "\"는 적지않기 *
* 서버 프로그램은 낮은 번호순으로 실행되고 종료시는 높은 번호 순으로 종료됨 *
*************************************************************************************************
[UpdateInfo]
UpdatePath=D:\inetpub\wwwroot\A3_update
[SvrInfo]
WinWaitSec=60
Interval=180
ServerMax=14
SvrPath0=D:\A3Server\E.ZoneServer\ZoneServer.exe,0,,,0
SvrPath1=D:\a3server\7770\asd_mw_v1.3.21a.exe,0,,,1
SvrPath2=D:\a3server\8880\asd_mw_v1.3.21a.exe,0,,,1
SvrPath3=D:\a3server\9990\asd_mw_v1.3.21a.exe,0,,,1
SvrPath4=D:\a3server\LoginServer\newLoginServer.exe,0,,,0
SvrPath5=D:\a3server\Loginagent\enLoginAgentr.exe,0,,,0
SvrPath6=D:\a3server\ZoneAgent\EnZa_v2.0.16a.exe,1,610,30,0
SvrPath7=D:\a3server\mainserver\MainServer.exe,0,,,0
SvrPath8=D:\a3server\A3_Util\FDB2Txt.exe,0,,,0
SvrPath9=D:\a3server\A3_Util\MWCLDB.exe,0,,,0
SvrPath10=D:\a3server\accountserver\AccountServer.exe,1,50,30,0
SvrPath11=D:\a3server\Zoneserver\ZoneServer.exe,0,,,0
SvrPath12=D:\a3server\BattleServer\BattleServer.exe,0,,,0
SvrPath13=D:\a3server\new\CenterServer.exe,0,,,0
SvrPath14=D:\a3server\Zoneserver\gmshouts.exe,0,,,2
SvrPath15=
Attachments
You must be registered for see attachments list