изучая новую версию 5.21
по мотивам Как найти символы в тексте?
насколько я понял тех.задание.
А что не понял - то в соответствии с моим представлением и опытом
--------------------
Nodes Monitor
1.
запускается, читает список IP-адресов из текстового файла IP.LST
запускает потоки для
- пингования адресов (период 10 сек) запись в Лог
- вывода на экран если есть пропуск ответов (период 10 сек)
- перечитывания файла IP.LST на предмет изменения списка (период 60 сек)
входит в цикл обработки событий окна
Изначально окно - скрыто.
Если есть неотвечающие ноды - окно проявляется.
В нем - список неотвечающих нодов
если все ноды опять отвечают - окно скрывается.
файл Nodes_Monitor.pb
#FILE_IP = 1
#PROG_NAME$="Nodes Monitor"
#WIN_TITLE$="Список неотвечающих нодов "
#DATE_FORMAT_1$="%yyyy/%mm/%dd %hh:%ii:%ss"
Structure NodeStatus
IP$
LastReplyStatus.l ;#True or #False
LastReplyDate.l
EndStructure
InitNetwork()
;----- Global vars ----------
;{
Global exeFile$=ProgramFilename()
Global glLogFile$=Left(exeFile$,Len(exeFile$)-4)+".log"
Global glIPlistFile$=GetPathPart(exeFile$)+"IP.lst"
Global glLogFileMutex=CreateMutex()
Global glNodeListMutex=CreateMutex()
Global NewList NodeList.NodeStatus()
Global glStopAllTreads=#False
Global glPingingTread, glDisplayThread, glConfigThread
Global glConfigDate
;}
Procedure.s Period(time)
Protected Secs=Mod(time,60)
Protected Mins=Mod(Int(time/60),60)
Protected Hours=Mod(Int(time/60/60),24)
Protected Days=Int(time/60/60/24)
Protected Result$=""
If Days>0: Result$=Str(Days)+"д": EndIf
If Hours>0: Result$+Str(Hours)+"ч": EndIf
If Mins>0: Result$+Str(Mins)+"м": EndIf
If Secs>0: Result$+Str(Secs)+"с": EndIf
ProcedureReturn Result$
EndProcedure
Procedure WriteToLog(entry.s)
Protected hFile.l, LenFile.q, MaxLen=51000, p, bytes, *Memory
LockMutex(glLogFileMutex)
hFile = OpenFile(#PB_Any, glLogFile$)
If hFile = #Null
UnlockMutex(glLogFileMutex)
MessageRequester("","No Open LogFile "+glLogFile$)
ProcedureReturn #False
EndIf
FileSeek(hFile, Lof(hFile))
WriteStringN(hFile, FormatDate(#DATE_FORMAT_1$, Date())+" "+entry)
;контроль размера файла
LenFile=Lof(hFile)
If LenFile>MaxLen ;50k
FlushFileBuffers(hFile)
*Memory = AllocateMemory(LenFile) ; allocate the needed memory
If *Memory
FileSeek(hFile, 0)
If ReadData(hFile, *Memory, LenFile) ; read all data into the memory block
For p=(LenFile-MaxLen) To (LenFile-1)
If PeekS(*Memory+p , 2, #PB_Ascii)=#CRLF$
CloseFile(hFile)
hFile = CreateFile(#PB_Any , glLogFile$)
If hFile
WriteData(hFile, *Memory+p, LenFile-p-1)
Break
EndIf
EndIf
Next
EndIf
EndIf
EndIf
CloseFile(hFile)
UnlockMutex(glLogFileMutex)
ProcedureReturn #True
EndProcedure
Procedure.b IsIP(IP$)
Protected Result=#True
Protected Fld1.w = Val(StringField(IP$, 1, "."))
Protected Fld2.w = Val(StringField(IP$, 2, "."))
Protected Fld3.w = Val(StringField(IP$, 3, "."))
Protected Fld4.w = Val(StringField(IP$, 4, "."))
If Fld1>255 Or Fld1<0 Or Fld2>255 Or Fld2<0 Or Fld3>255 Or Fld3<0 Or Fld4>255 Or Fld4<0
Result=#False
EndIf
ProcedureReturn Result
EndProcedure
Procedure.l Ping(IPAddr$, TimeOutMs)
nLib1=OpenLibrary( #PB_Any, "iphlpapi.dll")
nLib2=OpenLibrary( #PB_Any, "wsock32.dll")
If nLib1 And nLib2
SendData$ = "Test"
ReplyBuffer$ = Space(SizeOf(ICMP_ECHO_REPLY) + Len(SendData$) + SizeOf(character))
hIcmpFile = CallFunction(nLib1, "IcmpCreateFile")
nIP=CallFunction(nLib2, "inet_addr", @IPAddr$)
If nIP<>#INADDR_NONE
dwRetVal = CallFunction(nLib1, "IcmpSendEcho", hIcmpFile, nIP, @SendData$, Len(SendData$), #Null, @ReplyBuffer$, Len(ReplyBuffer$) + SizeOf(ICMP_ECHO_REPLY), TimeOutMs)
EndIf
CallFunction(nLib1, "IcmpCloseHandle", hIcmpFile)
CloseLibrary(nLib1)
CloseLibrary(nLib2)
If dwRetVal
ProcedureReturn 1
Else
ProcedureReturn 0
EndIf
EndIf
EndProcedure
Procedure Pinging(*par)
Repeat
LockMutex(glNodeListMutex)
;цикл опроса нодов
ForEach NodeList()
IP$=NodeList()\IP$
;MessageRequester("",IP$)
If ping(IP$,3000) ;timeOut
NodeList()\LastReplyDate=Date()
If NodeList()\LastReplyStatus=#False ;восстановились ответы
WriteToLog(IP$+" again reply")
EndIf
NodeList()\LastReplyStatus=#True
Else
If NodeList()\LastReplyStatus=#False ;уже в состоянии НЕ_ОТВЕЧАЕТ
Else
NodeList()\LastReplyStatus=#False ;установить в состояние НЕ_ОТВЕЧАЕТ
WriteToLog(IP$+" NOT REPLY")
EndIf
EndIf
If glStopAllTreads: UnlockMutex(glNodeListMutex): Break 2: EndIf
Next
UnlockMutex(glNodeListMutex)
n=0
While n<10
If glStopAllTreads: Break 2: EndIf
Delay(1000)
n+1
Wend
ForEver
EndProcedure
Procedure ListToLog()
LockMutex(glNodeListMutex)
WriteToLog("Список слежения")
ForEach NodeList(): WriteToLog(NodeList()\IP$): Next
UnlockMutex(glNodeListMutex)
EndProcedure
Procedure ConfigReader()
Protected result=#True
If ReadFile(#FILE_IP, glIPlistFile$)
glConfigDate=GetFileDate(glIPlistFile$, #PB_Date_Modified) ;запомнить дату
LockMutex(glNodeListMutex)
ClearList(NodeList())
While Not Eof(#FILE_IP)
t$=ReadString(#FILE_IP)
If IsIP(t$)
AddElement(NodeList())
NodeList()\IP$ = t$
NodeList()\LastReplyDate=Date()
NodeList()\LastReplyStatus=#True
EndIf
Wend
UnlockMutex(glNodeListMutex)
CloseFile(#FILE_IP)
Else
result=#False
EndIf
ProcedureReturn result
EndProcedure
Procedure ConfigMonitor(*par) ;проверка изменений в конфиг файле
Protected CurConfFileDate
Repeat
CurConfFileDate=GetFileDate(glIPlistFile$, #PB_Date_Modified)
;Debug "ConfigFile "+FormatDate(#DATE_FORMAT_1$,CurConfFileDate)
If glConfigDate<CurConfFileDate
WriteToLog("Изменилась дата файла IP.lst: "+FormatDate(#DATE_FORMAT_1$,glConfigDate)+"=>"+FormatDate(#DATE_FORMAT_1$,CurConfFileDate))
If ConfigReader()
ListToLog()
Else
WriteToLog( "Не найден файл <"+glIPlistFile$+"> с IP адресами" )
EndIf
EndIf
n=0
While n<60 ;ждать минуту
If glStopAllTreads: Break 2: EndIf
Delay(1000)
n+1
Wend
ForEver
EndProcedure
;----- IncludeFile -------------
IncludeFile "wMess.pbi"
Procedure Show(*par)
Repeat
LockMutex(glNodeListMutex)
;проверить необходимость показа
NeedShow=#False
ForEach NodeList()
If NodeList()\LastReplyStatus=#False
NeedShow=#True
Break
EndIf
Next
If NeedShow ; показать окно
;Debug "Есть пропуски "+FormatDate("%hh:%ii:%ss", Date())
SetActiveWindow(#Window_0)
ClearGadgetItems(#ListIcon_0)
; заполнить таблицу неотвечающих нодов
ForEach NodeList()
If NodeList()\LastReplyStatus=#False
t$=NodeList()\IP$+Chr(10)
t$+FormatDate(#DATE_FORMAT_1$,NodeList()\LastReplyDate)+Chr(10)
t$+Period(Date()-NodeList()\LastReplyDate)
AddGadgetItem(#ListIcon_0,-1,t$)
EndIf
If glStopAllTreads: UnlockMutex(glNodeListMutex): Break 2: EndIf
Next
SetWindowTitle(#Window_0, #WIN_TITLE$+" на "+FormatDate(#DATE_FORMAT_1$,Date()))
HideWindow(#Window_0,0)
Else
;Debug "Нет пропусков "+FormatDate("%hh:%ii:%ss", Date())
ClearGadgetItems(#ListIcon_0)
HideWindow(#Window_0,1)
EndIf
UnlockMutex(glNodeListMutex)
n=0
While n<10
If glStopAllTreads: Break 2: EndIf
Delay(1000)
n+1
Wend
ForEver
EndProcedure
HideWindow(#Window_0,1)
WriteToLog(#PROG_NAME$+" started ----------------")
If ConfigReader()
ListToLog()
Else
MessageRequester(#PROG_NAME$, "Не найден файл <"+glIPlistFile$+"> с IP адресами" ,#MB_OK|#MB_ICONERROR)
End
EndIf
If ListSize(NodeList())=0
MessageRequester(#PROG_NAME$, "Список допустимых IP-адресов - пуст"+#CRLF$+"Дальнейшая работа программы невозможна" ,#MB_OK|#MB_ICONERROR)
End
EndIf
glPingingTread=CreateThread(@Pinging(),0)
If glPingingTread=0
MessageRequester(#PROG_NAME$, "Облом при создании потока-опросчика"+#CRLF$+ErrorMessage()+#CRLF$+"Дальнейшая работа программы невозможна" ,#MB_OK|#MB_ICONERROR)
End
EndIf
glDisplayThread=CreateThread(@Show(),0)
If glDisplayThread=0
MessageRequester(#PROG_NAME$, "Облом при создании потока-индикатора"+#CRLF$+ErrorMessage()+#CRLF$+"Дальнейшая работа программы невозможна" ,#MB_OK|#MB_ICONERROR)
End
EndIf
glConfigThread=CreateThread(@ConfigMonitor(),0)
If glConfigThread=0
WriteToLog("Облом при создании потока - монитора конфигурации")
WriteToLog("Last Error:"+ErrorMessage())
End
EndIf
Repeat
event = WaitWindowEvent(100)
Until Window_0_Events(event) = #Falseфайл wMess.pbi - чуть подкуроченый код от ФормДизайнера
Enumeration #PB_Compiler_EnumerationValue
#Window_0
EndEnumeration
Enumeration #PB_Compiler_EnumerationValue
#ListIcon_0
#Font_A12
EndEnumeration
LoadFont(#Font_A12,"Arial", 12)
Procedure OpenWindow_0(x = 0, y = 0, width = 504, height = 160)
ExamineDesktops()
x = DesktopWidth(0)-width-10
y = DesktopHeight(0)-height-60
OpenWindow(#Window_0, x, y, width, height, "Список неотвечающих нодов", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_BorderLess )
HideWindow(#Window_0, 1)
SetWindowColor(#Window_0, RGB(255,255,0))
ListIconGadget(#ListIcon_0, 4, 0, 496, 156, "IP", 140, #PB_ListIcon_GridLines)
SetGadgetFont(#ListIcon_0, FontID(#Font_A12))
AddGadgetColumn(#ListIcon_0, 1, "Последний ответ был", 180)
AddGadgetColumn(#ListIcon_0, 2, "Прошло времени", 150)
EndProcedure
Procedure Window_0_Events(event)
Protected n
Select event
Case #PB_Event_CloseWindow
glStopAllTreads=#True
n=0
Repeat
Delay(1000)
If IsThread(glPingingTread) Or IsThread(glDisplayThread) Or IsThread(glConfigThread)
Delay(1000)
Else
Break
EndIf
n+1
Until n<10 ;ждать макс 10 сек
ProcedureReturn #False
EndSelect
ProcedureReturn #True
EndProcedure
OpenWindow_0()Если нажать X на окне - программа завершится с правильным закрытием потоков (хотя зачем это нужно?)
Нуждается в дальнейшей оптимизации
P.S.
Да потрет все это админ если недостойно