изучая новую версию 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.
Да потрет все это админ если недостойно