Guten Morgen,
AU3 hat ja eigene TCP/UDP-Anweisungen, die durchaus nützliche asynchrone Nachrichtenverarbeitung ist aber leider nicht dabei. Ich habe mich früher schon mal damit beschäftigt, und weil es in diesem Forum dazu noch nichts gibt, stelle ich das hier ein.
Client.au3
; --------------------------------------------------------------------------------------------------------------------------------
; TCP CLIENTSCRIPT
; --------------------------------------------------------------------------------------------------------------------------------
#include <GuiConstantsEx.au3>
#include <EditConstants.au3>
#include <ListBoxConstants.au3>
#include <StaticConstants.au3>
#include "TCP.au3"
; --------------------------------------------------------------------------------------------------------------------------------
; IP-Adresse und -Port des Servers:
Dim Const $ServerAddr = "127.0.0.1"
Dim Const $ServerPort = "8765"
; --------------------------------------------------------------------------------------------------------------------------------
; TCP initialisieren
If Not TCPStartup() Then
MsgBox(16, "TCP Client", "Fehler bei TCPStartup() -> " & @error)
Exit
EndIf
OnAutoItExitRegister("_Exit")
; --------------------------------------------------------------------------------------------------------------------------------
; GUI
Dim $aSplit = StringSplit($ServerAddr, ".")
Opt("GUIOnEventMode", 1)
$hGUI = GUICreate("TCP Client", 440, 350)
GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")
GUICtrlCreateLabel("Socket", 10, 10, 50)
GUICtrlSetColor(-1, 0x000080)
GUICtrlCreateLabel("Text", 70, 10, 300)
GUICtrlSetColor(-1, 0x000080)
$idSocket = GUICtrlCreateEdit("", 10, 30, 50, 20, $ES_READONLY)
GUICtrlSetState(-1, $GUI_DISABLE)
$idData = GUICtrlCreateInput("", 70, 30, 300, 20)
GUICtrlSetState(-1, $GUI_DISABLE)
$idSend = GUICtrlCreateButton("Send", 380, 30, 50, 20)
GUICtrlSetState(-1, $GUI_DEFBUTTON)
GUICtrlSetState(-1, $GUI_DISABLE)
GUICtrlSetOnEvent(-1, "_Send")
$idLOG = GUICtrlCreateEdit("Not connected!", 10, 60, 420, 250, $ES_READONLY)
GUICtrlCreateLabel("IP:", 10, 320, -1, -1, $SS_CENTERIMAGE)
GUICtrlSetColor(-1, 0x000080)
$idIP1 = GUICtrlCreateInput($aSplit[1], 30, 320, 30, 20, $ES_NUMBER + $ES_CENTER)
GUICtrlSetLimit(-1, 3)
$idIP2 = GUICtrlCreateInput($aSplit[2], 70, 320, 30, 20, $ES_NUMBER + $ES_CENTER)
GUICtrlSetLimit(-1, 3)
$idIP3 = GUICtrlCreateInput($aSplit[3], 110, 320, 30, 20, $ES_NUMBER + $ES_CENTER)
GUICtrlSetLimit(-1, 3)
$idIP4 = GUICtrlCreateInput($aSplit[4], 150, 320, 30, 20, $ES_NUMBER + $ES_CENTER)
GUICtrlSetLimit(-1, 3)
GUICtrlCreateLabel("Port:", 200, 320, -1, -1, $SS_CENTERIMAGE)
GUICtrlSetColor(-1, 0x000080)
$idPort = GUICtrlCreateInput($ServerPort, 230, 320, 50, 20, $ES_NUMBER + $ES_CENTER)
GUICtrlSetLimit(-1, 5)
$idConnect = GUICtrlCreateButton("Connect", 350, 320, 80, 22)
GUICtrlSetOnEvent(-1, "_Connect")
GUISetState()
; --------------------------------------------------------------------------------------------------------------------------------
; Routine für die Behandlung der Notifications registrieren
GUIRegisterMsg(_TCP_MessageNum(), "_NewTPCEvent")
; --------------------------------------------------------------------------------------------------------------------------------
While True
Sleep(1000)
WEnd
; --------------------------------------------------------------------------------------------------------------------------------
Func _Connect()
Local $Enable, $Disable, $IP, $Item, $Port, $Socket
Local $Action = GUICtrlRead($idConnect)
Switch $Action
Case "Connect"
$IP = GUICtrlRead($idIP1) & "." & GUICtrlRead($idIP2) & "." & GUICtrlRead($idIP3) & "." & GUICtrlRead($idIP4)
$Port = GUICtrlRead($idPort)
$Socket = TCPConnect($IP, $Port)
If $Socket < 1 Then
MsgBox(16, "TCP Client", "Fehler bei TCPConnect() -> " & @error, 0, $hGUI)
Return $GUI_RUNDEFMSG
EndIf
; --------------------------------------------------------------------------------------------------------------------
; Asynchrone Eventverarbeitung per Notification aktivieren
If Not _TCP_AsyncSelect($Socket, @GUI_WinHandle, _TCP_MessageNum(), "FD_CLOSE|FD_CONNECT|FD_READ") Then
MsgBox(16, "TCP Server", "Fehler bei _TCP_AsyncSelect() -> " & _TCP_GetLastError(), 0, $hGUI)
Return $GUI_RUNDEFMSG
EndIf
$Enable = $GUI_ENABLE
$Disable = $GUI_DISABLE
GUICtrlSetData($idConnect, "Disconnect")
GUICtrlSetData($idSocket, $Socket)
_UpdateLog($Socket & " >>> Connected to " & $IP & ":" & $Port)
Case Else
$Socket = GUICtrlRead($idSocket)
; --------------------------------------------------------------------------------------------------------------------
; Asynchrone Eventverarbeitung per Notification deaktivieren
If Not _TCP_AsyncSelect($Socket, @GUI_WinHandle, 0, 0) Then
MsgBox(16, "TCP Server", "Fehler bei _TCP_AsyncSelect() -> " & _TCP_GetLastError(), 0, $hGUI)
Return $GUI_RUNDEFMSG
EndIf
If Not TCPCloseSocket($Socket) Then
MsgBox(16, "TCP Client", "Fehler bei TCPCloseSocket() -> " & @error, 0, $hGUI)
Return $GUI_RUNDEFMSG
EndIf
$Enable = $GUI_DISABLE
$Disable = $GUI_ENABLE
GUICtrlSetData($idConnect, "Connect")
GUICtrlSetData($idSocket, "")
_UpdateLog($Socket & " >>> Connection closed!")
EndSwitch
GUICtrlSetState($idSocket, $ENABLE)
GUICtrlSetState($idData, $ENABLE)
GUICtrlSetState($idSend, $ENABLE)
GUICtrlSetState($idIP1, $DISABLE)
GUICtrlSetState($idIP2, $DISABLE)
GUICtrlSetState($idIP3, $DISABLE)
GUICtrlSetState($idIP4, $DISABLE)
GUICtrlSetState($idPort, $DISABLE)
If $Action = "Connect" Then
GUICtrlSetState($idData, $GUI_FOCUS)
Else
GUICtrlSetState($idIP1, $GUI_FOCUS)
EndIf
EndFunc
; --------------------------------------------------------------------------------------------------------------------------------
Func _Exit()
TCPShutdown()
Exit
EndFunc
; --------------------------------------------------------------------------------------------------------------------------------
Func _NewTPCEvent($hWnd, $iMsg, $wParam, $lParam)
; Zuerst wird die Eventhandler-Routine aufgerufen, um das Event zu verarbeiten, ...
Local $Data = _TCP_EventHandler($hWnd, $iMsg, $wParam, $lParam)
; ... dann können wir machen, was wir wollen!
If $Data Then _UpDateLog($Data)
EndFunc
; --------------------------------------------------------------------------------------------------------------------------------
Func _Send()
Local $Socket, $Data
$Socket = GUICtrlRead($idSocket)
$Data = GUICtrlRead($idData)
If Not TCPSend($Socket, $Data) Then
MsgBox(16, "TCP Client", "Fehler bei TCPSend() -> " & @error, 0, $hGUI)
Else
_UpdateLog($Socket & " >>> " & $Data)
EndIf
GUICtrlSetData($idData, "")
GUICtrlSetState($idData, $GUI_FOCUS)
EndFunc
; --------------------------------------------------------------------------------------------------------------------------------
Func _UpdateLog($Data)
Global $idLOG
GUICtrlSendMsg($idLOG, $EM_SETSEL, -2, -1)
GUICtrlSetData($idLOG, @CRLF & $Data, 1)
EndFunc
Server.au3
; --------------------------------------------------------------------------------------------------------------------------------
; TCP SERVERSCRIPT
; --------------------------------------------------------------------------------------------------------------------------------
#include <GuiConstantsEx.au3>
#include <ComboConstants.au3>
#include <EditConstants.au3>
#include <WindowsConstants.au3>
#include "TCP.au3"
; --------------------------------------------------------------------------------------------------------------------------------
; IP-Adresse und Port des servers:
Dim Const $IPAddr = "127.0.0.1"
Dim Const $IPPort = "8765"
; --------------------------------------------------------------------------------------------------------------------------------
; TCP initialisieren
If Not TCPStartup() Then
MsgBox(16, "TCP Server", "Fehler bei TCPStartup() -> " & @error)
Exit
EndIf
OnAutoItExitRegister("_Exit")
; --------------------------------------------------------------------------------------------------------------------------------
; Listener für Server erzeugen
Dim $Listener = TCPListen($IPAddr, $IPPort)
If @error Or $Listener < 1 Then
MsgBox(16, "TCP Server", "Fehler bei TCPListen() -> " & @error)
Exit
EndIf
; --------------------------------------------------------------------------------------------------------------------------------
; GUI
Opt("GUIOnEventMode", 1)
$hGUI = GUICreate("TCP Server " & $IPAddr & ":" & $IPPort , 460, 320)
GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")
GUICtrlCreateLabel("Socket", 10, 10, 50)
GUICtrlSetColor(-1, 0x000080)
GUICtrlCreateLabel("Text", 90, 10, 300)
GUICtrlSetColor(-1, 0x000080)
$idSocket = GUICtrlCreateCombo("", 10, 30, 70, -1, BitOR($CBS_DROPDOWNLIST, $CBS_SORT, $WS_VSCROLL))
$idData = GUICtrlCreateInput("", 90, 30, 300, 20)
GUICtrlSetState($idData, $GUI_FOCUS)
$idSend = GUICtrlCreateButton("Send", 400, 30, 50, 20)
GUICtrlSetState(-1, $GUI_DEFBUTTON)
GUICtrlSetOnEvent(-1, "_Send")
$idLOG = GUICtrlCreateEdit("Waiting for connections ...", 10, 60, 440, 250, $ES_READONLY)
GUISetState()
; --------------------------------------------------------------------------------------------------------------------------------
; Asynchrone Eventverarbeitung per Notification aktivieren, der Server muss zunächst einmal per "FD_ACCEPT"
; gemeldete Verbindungswünsche akzeptieren
If Not _TCP_AsyncSelect($Listener, $hGUI, _TCP_MessageNum(), "FD_ACCEPT") Then
MsgBox(16, "TCP Server", "Fehler bei _TCP_AsyncSelect() -> " & _TCP_GetLastError(), 0, $hGUI)
Exit
EndIf
; --------------------------------------------------------------------------------------------------------------------------------
; Routine für die Behandlung der Notifications registrieren
GUIRegisterMsg(_TCP_MessageNum(), "_NewTPCEvent")
; --------------------------------------------------------------------------------------------------------------------------------
While True
Sleep(1000)
WEnd
; --------------------------------------------------------------------------------------------------------------------------------
Func _Exit()
TCPShutdown()
Exit
EndFunc
; --------------------------------------------------------------------------------------------------------------------------------
Func _NewTPCEvent($hWnd, $iMsg, $wParam, $lParam)
Local Static $FD_ACCEPT = 8 ; Notification of incoming connections.
Local Static $FD_CLOSE = 32 ; Notification when connection has been closed.
Local $ThisEvent = BitAND($lParam, 0xFFFF)
Local $Data = _TCP_EventHandler($hWnd, $iMsg, $wParam, $lParam)
Switch $ThisEvent
Case $FD_ACCEPT
If StringInStr($Data, "accepted") Then
Local $aRX = StringRegExp($Data, "\A(\d+)", 1)
GUICtrlSetData($idSocket, $aRX[0], $aRX[0])
GUICtrlSetState($idData, $GUI_FOCUS)
EndIf
Case $FD_CLOSE
If StringInStr($Data, "closed") Then
Local $aRX = StringRegExp($Data, "\A(\d+)", 1)
Local $Index = GUICtrlSendMsg($idSocket, $CB_FINDSTRING, -1, $aRX[0])
If $Index > -1 Then
GUICtrlSendMsg($idSocket, $CB_DELETESTRING, $Index, 0)
GUICtrlSendMsg($idSocket, $CB_SETCURSEL, 0, 0)
GUICtrlSetState($idSend, $GUI_SHOW)
EndIf
GUICtrlSetState($idData, $GUI_FOCUS)
EndIf
EndSwitch
_UpDateLog($Data)
EndFunc
; --------------------------------------------------------------------------------------------------------------------------------
Func _Send()
Local $Socket, $Data
$Socket = GUICtrlRead($idSocket)
If $Socket Then
$Data = GUICtrlRead($idData)
If Not TCPSend($Socket, $Data) Then
MsgBox(16, "TCP Client", "Fehler bei TCPSend() -> " & @error, 0, $hGUI)
Else
_UpdateLog($Socket & " >>> " & $Data)
EndIf
EndIf
GUICtrlSetData($idData, "")
GUICtrlSetState($idData, $GUI_FOCUS)
EndFunc
; --------------------------------------------------------------------------------------------------------------------------------
Func _UpdateLog($Data)
Global $idLOG
GUICtrlSendMsg($idLOG, $EM_SETSEL, -2, -1)
GUICtrlSetData($idLOG, @CRLF & $Data, 1)
EndFunc
TCP.au3
; #INDEX# =======================================================================================================================
; Title .........: TCP
; AutoIt Version : 3.3.6.1
; Language ......: Deutsch
; Description ...: Funktionen für die asynchrone Verarbeitung von TCP-Events per "notification messages"
; Author(s) .....: Großvater (http://www.autoit.de)
; Dll(s) ........: WS2_32.dll
; ===============================================================================================================================
; #CURRENT# =====================================================================================================================
;_TCP_AsyncSelect
;_TCP_EventHandler
;_TCP_GetLastError
;_TCP_MessageNum
; ===============================================================================================================================
; #FUNCTION# ====================================================================================================================
; Name...........: _TCP_AsyncSelect
; Description ...: Registriert eine "notification message" für einen Socket und vorgegebene TCP-Events
; Syntax.........: _TCP_AsyncSelect($Socket, $hWnd, $Msg, $Events)
; Parameters ....: $Socket - gültiger TCP-Socket
; $hWnd - hWnd des Fensters, dem die Nachricht gesendet wird
; $Msg - Nachrichtennummer für die "notification message" (sollte zwischen 0x1000 und 0x7FFF liegen)
; $Events - String mit durch Pipe (|) getrennter Liste von TCP-Events.
; Z.Zt. werden folgende Events unterstützt:
; FD_ACCEPT : Server: eingehende Verbindung
; FD_CLOSE : Client/Server: Verbindung wurde beendet
; FD_CONNECT : Client: erfolgreiche Verbindung
; FD_READ : Client/Server: Daten wurden empfangen
; Return values .: Erfolg - True
; Fehler - False
; Author ........: Großvater (http://www.autoit.de)
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ===============================================================================================================================
Func _TCP_AsyncSelect($Socket, $hWnd, $Msg, $Events)
Local Static $FD_READ = 1 ; Daten wurden empfangen
Local Static $FD_ACCEPT = 8 ; Verbindungswunsch wurde empfangen
Local Static $FD_CONNECT = 16 ; Verbindung wurde erfolgreich aufgebaut
Local Static $FD_CLOSE = 32 ; Verbindung wurde getrennt
Local $ThisEvents = 0
Local $aSplit = StringSplit($Events, "|")
For $I = 1 To $aSplit[0]
If IsDeclared($aSplit[$I]) Then $ThisEvents += Eval($aSplit[$I])
Next
Local $aResult = DllCall("Ws2_32.dll", "Int", "WSAAsyncSelect", "UInt", $Socket, "UInt", $hWnd, "Int", $Msg, "Int", $ThisEvents)
If $aResult[0] Then Return False
Return True
EndFunc
; #FUNCTION# ====================================================================================================================
; Name...........: _TCP_EventHandler
; Description ...: Eventhandler für die mit _TCP_AsyncSelect() registrierten Events.
; Syntax.........: _TCP_EventHandler($hWnd, $Msg, $Socket, $lParam)
; Parameters ....: $hWnd - hWnd des Fensters, dem die Nachricht gesendet wurde
; $Msg - Nachrichtennummer
; $Socket - TCP-Socket (wParam)
; $lParam - zusätzliche Informationen:
; Low Word : TCP-Event
; High Word: TCP-Error
; Return values .: Erfolg - eventabhängige Meldung
; Fehler - False
; Author ........: Großvater (http://www.autoit.de)
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ===============================================================================================================================
Func _TCP_EventHandler($hWnd, $Msg, $Socket, $lParam)
Local Static $FD_READ = 1 ; Daten wurden empfangen
Local Static $FD_ACCEPT = 8 ; Verbindungswunsch wurde empfangen
Local Static $FD_CONNECT = 16 ; Verbindung wurde erfolgreich aufgebaut
Local Static $FD_CLOSE = 32 ; Verbindung wurde getrennt
Local Static $WSAEWOULDBLOCK = 10035
Local Static $WSAECONNRESET = 10054
Local Static $MaxData = 4096 ; Maximallänge für die empfangenen Daten in Bytes
Local $ThisEvent = BitAND($lParam, 0xFFFF)
Local $ThisError = BitShift($lParam, 16)
Switch $ThisEvent
Case $FD_ACCEPT
Local $NewSocket = TCPAccept($Socket)
If $NewSocket = -1 Then
TCPSend($NewSocket, "Connection rejected!")
Return Number($NewSocket) & " >>> Connection rejected!"
Else
_TCP_AsyncSelect($NewSocket, $hWnd, _TCP_MessageNum(), "FD_CLOSE|FD_CONNECT|FD_READ")
TCPSend($NewSocket, "Connection accepted!")
Return Number($NewSocket) & " >>> Connection accepted!"
EndIf
Case $FD_CLOSE
TCPCloseSocket($Socket)
Return Number($Socket) & " >>> Connection closed!"
Case $FD_CONNECT
Return Number($Socket) & " >>> Connection accepted!"
Case $FD_READ
Local $Buffer = ""
Local $Received = TCPRecv($Socket, $MaxData)
While $Received And Not @error
$Buffer &= $Received
$Received = TCPRecv($Socket, $MaxData)
WEnd
If @error Then
Switch @error
Case $WSAEWOULDBLOCK ; WSAEWOULDBLOCK (keine weiteren Daten vorhanden, gibt es nicht unter AU3!!!)
Case Not $WSAECONNRESET ; WSAECONNRESET (der Netzwerkdienst wurde vom System beendet)
; Unerwartete Fehler werden gemeldet
MsgBox(0, "TCP Error", "recv() indicated Winsock error " & @error)
Exit
EndSwitch
EndIf
If $Buffer Then Return Number($Socket) & " <<< " & $Buffer
EndSwitch
Return False
EndFunc
; #FUNCTION# ====================================================================================================================
; Name...........: _TCP_GetLastError
; Description ...: Letzten TCP-Fehlercode holen.
; Syntax.........: _TCP_GetLastError()
; Parameters ....:
; Return values .: WSA Errorcode
; Author ........: Großvater (http://www.autoit.de)
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ===============================================================================================================================
Func _TCP_GetLastError()
Local $aResult = DllCall("Ws2_32.dll", "Int", "WSAGetLastError")
Return $aResult[0]
EndFunc
; #FUNCTION# ====================================================================================================================
; Name...........: _TCP_MessageNum
; Description ...: Vordefinierte Nachrichtennummer holen/setzen
; Syntax.........: _TCP_MessageNum([$iMsgNum = 0])
; Parameters ....: $iMsgNum - Neue Nachrichtennummer
; Return values .: Nachrichtennummer
; Author ........: Großvater (http://www.autoit.de)
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ===============================================================================================================================
Func _TCP_MessageNum($iMsgNum = 0)
Local Static $TCPMsg = 0x5555
If ($iMsgNum) Then $TCPMsg = $iMsgNum
Return $TCPMsg
EndFunc
Ich hoffe, die enthaltenen Kommentare erklären das Ganze ausreichend, wenn nicht, einfach fragen.