- Сообщения
- 1,590
- Репутация
- 341
Суть такая, повышаю скилл в TCP, однако уже сутки бьюсь над стабильной работой программы. Программа нужна для работы - администрирование компьютерного класса. Принцип работы: отправляем с сервера команду в виде AutoIT-кода и все компьютеры в сети его выполняют.
Хочу сделать так, чтобы клиенты ждали пока серверная программа появится в сети и отдаст команду, и ждали его даже при повторных перезапусках серверной программы.
То же самое с серверной программой, должна принимать все соединения, и если сокет клиента стал недоступен - удалять из списка.
Основу программы написать удалось. Все работает, но только если ничего не закрывать, и то бывают ошибки. Если пробовать что то перезапускать. поведение программы становится непредсказуемым. Есть у кого нибудь какие идеи?
Сервер:
Клиент:
P.S. Да, я знаю что можно придумать варианты проще, но хочу сделать через TCP-на данный момент.
Хочу сделать так, чтобы клиенты ждали пока серверная программа появится в сети и отдаст команду, и ждали его даже при повторных перезапусках серверной программы.
То же самое с серверной программой, должна принимать все соединения, и если сокет клиента стал недоступен - удалять из списка.
Основу программы написать удалось. Все работает, но только если ничего не закрывать, и то бывают ошибки. Если пробовать что то перезапускать. поведение программы становится непредсказуемым. Есть у кого нибудь какие идеи?
Сервер:
Код:
#pragma compile(Console, False)
#pragma compile(x64, False)
#pragma compile(ExecLevel, AsInvoker)
#pragma compile(AutoItExecuteAllowed, False)
#pragma compile(Stripper, True)
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
#include <EditConstants.au3>
#include <Array.au3>
#include <Misc.au3>
#include <GuiListView.au3>
Opt("TCPTimeout", 20)
AdlibRegister("RegisterComputers", 1000)
TCPStartup()
OnAutoItExitRegister("OnAutoItExit")
Global $sIPAddress = @IPAddress1
Global $iPort = 65431, $iClientPort = 65432, $iError = 0
Dim $aConnectedComputers[1][3] = [[0, "ClientConnect", "ListenPort"]]
Global $iListenSocket = TCPListen($sIPAddress, $iPort, 20)
$sTitle = "Администрирование компьютерного класса"
$hGUI = GUICreate($sTitle, 800, 200)
$idText = GUICtrlCreateEdit("Ожидание подключения компьютеров...", 10, 10, 580, 145, BitOR($ES_WANTRETURN, $ES_READONLY))
$idInput = GUICtrlCreateInput("", 10, 165, 495, 25)
GUICtrlSendMsg($idInput, $EM_SETCUEBANNER, True, "Отправить команду ...")
$idBtnSend = GUICtrlCreateButton("Send", 510, 165, 80, 25)
$hList = GUICtrlCreateListView("Компьютеры", 600, 10, 190, 180)
_GUICtrlListView_SetColumnWidth($hList, 0, 180)
GUISetState(@SW_SHOW, $hGUI)
While 1
If _IsPressed('0D') Then _Send()
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE
ExitLoop
Case $idBtnSend
_Send()
EndSwitch
WEnd
Func _Send()
For $i = 1 To $aConnectedComputers[0][0]
TCPSend($aConnectedComputers[$i][1], GUICtrlRead($idInput))
If @error Then
ConsoleWrite("Send Error: " & @error & @CRLF)
_Delete($i)
EndIf
Next
GUICtrlSetData($idInput, '')
EndFunc ;==>_Send
Func RegisterComputers()
Local $iSocket, $_sIP
$iSocket = TCPAccept($iListenSocket)
If @error Then
_LogSetText("Could not accept the incoming connection, Error code: " & @error)
Else
If $iSocket = -1 Then Return
$_sIP = SocketToIP($iSocket)
_ArrayAdd($aConnectedComputers, $_sIP)
$aConnectedComputers[0][0] = UBound($aConnectedComputers) - 1
_GUICtrlListView_AddItem($hList, $_sIP)
For $i = 1 To $aConnectedComputers[0][0]
If Not $aConnectedComputers[$i][1] Then
$aConnectedComputers[$i][1] = TCPConnect($aConnectedComputers[$i][0], $iClientPort)
$aConnectedComputers[$i][2] = $iSocket
If @error Then
ConsoleWrite("Connect Error: " & @error & @CRLF)
_Delete($i)
Return
EndIf
EndIf
$sRecv = TCPRecv($aConnectedComputers[$i][2], 1024)
If @error Then
ConsoleWrite("Recv Error: " & @error & @CRLF)
_Delete($i)
Return
EndIf
If $sRecv Then _LogSetText($sRecv)
Next
EndIf
TCPCloseSocket($iSocket)
EndFunc ;==>RegisterComputers
Func _Delete($iIndex)
_ArrayDelete($aConnectedComputers, $iIndex)
$aConnectedComputers[0][0] = UBound($aConnectedComputers) - 1
EndFunc
Func OnAutoItExit()
TCPCloseSocket($iListenSocket)
TCPShutdown()
EndFunc ;==>OnAutoItExit
Func SocketToIP($iSocket)
Local $tSockAddr = 0, $aRet = 0
$tSockAddr = DllStructCreate("short;ushort;uint;char[8]")
$aRet = DllCall("Ws2_32.dll", "int", "getpeername", "int", $iSocket, "struct*", $tSockAddr, "int*", DllStructGetSize($tSockAddr))
If Not @error And $aRet[0] = 0 Then
$aRet = DllCall("Ws2_32.dll", "str", "inet_ntoa", "int", DllStructGetData($tSockAddr, 3))
If Not @error Then Return $aRet[0]
EndIf
Return 0
EndFunc ;==>SocketToIP
Func _LogSetText($sText)
GUICtrlSetData($idText, GUICtrlRead($idText) & @CRLF & $sText)
EndFunc ;==>_LogSetText
Клиент:
Код:
#pragma compile(ExecLevel, AsInvoker)
#pragma compile(AutoItExecuteAllowed, True)
#pragma compile(InputBoxRes, False)
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
#include <Array.au3>
TCPStartup()
Opt("TCPTimeout", 10)
OnAutoItExitRegister("OnAutoItExit")
Global $sIPAddress = @IPAddress1, $sServerIPAddress = @IPAddress1 ;"10.1.10.188"
Global $iServerPort = 65431, $iPort = 65432
Global $iSocket = 0, $iListenSocket = 0, $iConnectSocket = 0
Global $iLSocket = 0
_TryConnect($sServerIPAddress, $iServerPort)
Global $iListenSocket = TCPListen($sIPAddress, $iPort, 2)
If @error Then _Log("Could not listen, Error code: " & @error)
While 1
$iSocket = TCPAccept($iListenSocket)
If @error Then
_Log("Could not accept the incoming connection, Error code: " & @error & " Try New Connect")
_TryConnect($sServerIPAddress, $iServerPort)
Else
If Not ($iSocket = -1) Then $iLSocket = $iSocket
$sRecv = TCPRecv($iLSocket, 1024)
If @error Then
_Log("Recv Error: " & @error & " Try to reconnect")
EndIf
If $sRecv Then
Run(@ScriptFullPath & ' /AutoIt3ExecuteLine ' & $sRecv)
Sleep(100)
If WinExists("AutoIt Error") Then
TCPSend($iConnectSocket, $sIPAddress & " - Script Error")
ControlClick("AutoIt Error", "", "[CLASS:Button; ID:2]")
EndIf
EndIf
EndIf
WEnd
Func _TryConnect($_sServerIPAddress, $_iPort)
If $iConnectSocket <> 0 Then
TCPCloseSocket($iConnectSocket)
$iConnectSocket = 0
EndIf
While 1
$iConnectSocket = TCPConnect($_sServerIPAddress, $_iPort)
If Not @error Then
TCPSend($iConnectSocket, $sIPAddress & " - подключен")
ExitLoop
EndIf
WEnd
EndFunc ;==>_TryConnect
Func OnAutoItExit()
TCPSend($iConnectSocket, $sIPAddress & " - отключен")
TCPCloseSocket($iListenSocket)
TCPCloseSocket($iConnectSocket)
TCPShutdown()
EndFunc ;==>OnAutoItExit
Func _Log($sLogText)
FileWriteLine("Log.txt", $sLogText)
EndFunc
P.S. Да, я знаю что можно придумать варианты проще, но хочу сделать через TCP-на данный момент.