binarydigit0101 Posted August 22, 2013 Share Posted August 22, 2013 hello to everybody! yesterday, I found this post: '?do=embed' frameborder='0' data-embedContent>> ... where that server can accept requests from many users. I tried to make my code more or less like that but it doesn't work. now, telling you I tried but I didn't understand it so well, how can the code serves a client and listen to new connections at the same time? I guess AutoIT has a single thread, so if it is doing a thing, can't do one more. can you help me to understand how it can do? thank you so much ehi ehi ehi, what is your name? Link to comment Share on other sites More sharing options...
FireFox Posted August 22, 2013 Share Posted August 22, 2013 Let me make an example. Link to comment Share on other sites More sharing options...
Gianni Posted August 22, 2013 Share Posted August 22, 2013 Hi binarydigit0101 Also take a look >here bye Chimp small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt.... Link to comment Share on other sites More sharing options...
binarydigit0101 Posted August 22, 2013 Author Share Posted August 22, 2013 Let me make an example. do you need an example? Hi binarydigit0101 Also take a look >here bye alright, thank you. but where is the part about multi users? ehi ehi ehi, what is your name? Link to comment Share on other sites More sharing options...
FireFox Posted August 22, 2013 Share Posted August 22, 2013 do you need an example?LOL. No I meant I will post an example. Link to comment Share on other sites More sharing options...
binarydigit0101 Posted August 22, 2013 Author Share Posted August 22, 2013 LOL. No I meant I will post an example. I am sorry ehi ehi ehi, what is your name? Link to comment Share on other sites More sharing options...
FireFox Posted August 22, 2013 Share Posted August 22, 2013 (edited) Here is an advanced example, you can send commands which will be separately interpreted. A few notes: To detect the commands (or packets, whatever you call them), I set a header code and a footer code : {SOD}, {EOD} (for Start Of Data and End Of Data). These codes mustn't be present in the command itself, otherwise the command won't be correctly interpreted. If someone need a workaround on this, he can add the length of the command inside the header code e.g : {SOD:382} so that it will take the next 382 chars (then a footer code is not needed). Server: expandcollapse popup#include <WindowsConstants.au3> #include <GUIConstants.au3> #include <Constants.au3> #include <GUIListView.au3> #include <GUIEdit.au3> #include <GUIMenu.au3> #include <Date.au3> #include <String.au3> Example() Func Example() ; Start the TCP service. TCPStartup() ; Register OnAutoItExit to be called when the script is closed. OnAutoItExitRegister("OnAutoItExit") ; Set the maximum of clients (and pending connections). Global Const $_iMaxClients = 100 ; Assign a Local variable the socket and bind to the IP Address and Port specified with a maximum of $_iMaxClients pending connexions. Local $iListenSocket = TCPListen(@IPAddress1, 65432, $_iMaxClients) ; If an error occurred display the error code and return False. If @error Then Local $iError = @error MsgBox(BitOR($MB_SYSTEMMODAL, $MB_ICONHAND), "", "Could not listen, Error code: " & $iError) Return False EndIf Global $_sLogsDir = @ScriptDir & "\Logs" If FileExists($_sLogsDir) = 0 Then DirCreate($_sLogsDir) Global $_aClient[$_iMaxClients][6] Global Enum $_iClientSubIdx_Socket, $_iClientSubIdx_ComputerName, $_iClientSubIdx_FileHandle, $_iClientSubIdx_RecvBuffer, $_iClientSubIdx_Item, $_iClientSubIdx_LogLen Global $_iLastClientLog = -1 Global Enum $_CM_DISCONNECT = 1000 #region GUIMain AutoItSetOption("GUIOnEventMode", 1) Global $_hGUIMain = GUICreate("TCP server with multiple clients") GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit") Global $_iLwClient = GUICtrlCreateListView("Client|Date", 10, 10, 380, 380) Global $_hLwClient = GUICtrlGetHandle($_iLwClient) _GUICtrlListView_SetColumnWidth($_hLwClient, 0, 200) _GUICtrlListView_SetColumnWidth($_hLwClient, 1, 130) Global $_iDyContextMenu = GUICtrlCreateDummy() GUICtrlSetOnEvent($_iDyContextMenu, "_Dummy_ContextMenu") GUIRegisterMsg($WM_CONTEXTMENU, "WM_CONTEXTMENU") GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") GUISetState(@SW_SHOW, $_hGUIMain) #endregion GUIMain #region GUILog Global $_hGUILog = GUICreate("", 600, 300, -1, -1, BitOR($GUI_SS_DEFAULT_GUI, $WS_SIZEBOX), -1, $_hGUIMain) GUISetOnEvent($GUI_EVENT_CLOSE, "_GUILog_Hide") Global $_iEditLog = GUICtrlCreateEdit("", 0, 0, 600, 300, BitOR($WS_HSCROLL, $WS_VSCROLL, $ES_MULTILINE, $ES_READONLY, $ES_WANTRETURN)) GUICtrlSetResizing($_iEditLog, $GUI_DOCKBORDERS) Global $_hEditLog = GUICtrlGetHandle($_iEditLog) #endregion GUILog Local $iSocket = 0, $vRecv = "", $sIPAddress = "", $aData = 0, $iEODPos = 0, $sLogRead = "", $iPos = 0, $sPacket = "", $fProcessBuffer = False While 1 Sleep(10) ; Accept incomming connexions if present (Socket to close when finished; one socket per client). $iSocket = TCPAccept($iListenSocket) ; If an error occurred display the error code and exit the loop. If @error Then MsgBox(BitOR($MB_SYSTEMMODAL, $MB_ICONHAND), "", "Could not accept the incoming connection, Error code: " & @error) ExitLoop EndIf ; If a new client is connected. If $iSocket <> -1 Then For $i = 0 To $_iMaxClients - 1 If($_aClient[$i][$_iClientSubIdx_Socket] <> "") Then ContinueLoop GUICtrlCreateListViewItem(SocketToIP($iSocket) & "|" & _Now(), $_iLwClient) $_aClient[$i][$_iClientSubIdx_Item] = _GUICtrlListView_GetItemCount($_hLwClient) - 1 $_aClient[$i][$_iClientSubIdx_Socket] = $iSocket ExitLoop Next EndIf ; Loop through the connected clients. For $i = 0 To $_iMaxClients - 1 If($_aClient[$i][$_iClientSubIdx_Socket] = "") Then ContinueLoop ; Receive from the client a maximum of 4 KiB data. $vRecv = TCPRecv($_aClient[$i][$_iClientSubIdx_Socket], 4096) ; If an error occurred disconnect the client and process the next one. If @error Then _Client_Disconnect($i) ContinueLoop EndIf $fProcessBuffer = False ; If nothing is received. If $vRecv = "" Then ; If the buffer is not empty, set the processbuffer variable to true. If $_aClient[$i][$_iClientSubIdx_RecvBuffer] <> "" Then $fProcessBuffer = True ; Move the client buffer to the receive variable. $vRecv = $_aClient[$i][$_iClientSubIdx_RecvBuffer] $_aClient[$i][$_iClientSubIdx_RecvBuffer] = "" Else ; Process the next client. ContinueLoop EndIf EndIf ; The TCPRecv function can return a string or a binary, if binary then convert it to string. If IsBinary($vRecv) = 1 Then $vRecv = BinaryToString($vRecv) ; If the data is not a new packet. If StringLeft($vRecv, 5) <> "{SOD}" Then ; If the client has not received a packet header. If $_aClient[$i][$_iClientSubIdx_RecvBuffer] = "" Then ; If it's not a process buffer, disconnect the client and process the next one If Not $fProcessBuffer Then _Client_Disconnect($i) EndIf ContinueLoop EndIf EndIf ; Get the position of the packet footer. $iEODPos = StringInStr($vRecv, "{EOD}", 2) ;$STR_NOCASESENSEBASIC ; If the packet is incomplete, add it to the buffer and process the next client. If $iEODPos = 0 Then $_aClient[$i][$_iClientSubIdx_RecvBuffer] &= $vRecv ContinueLoop Else ; Assign the packet variable the end of the/full packet. $sPacket = $_aClient[$i][$_iClientSubIdx_RecvBuffer] & StringLeft($vRecv, $iEODPos - 1) ; Fill the buffer with the rest of the packet. $_aClient[$i][$_iClientSubIdx_RecvBuffer] = StringTrimLeft($vRecv, $iEODPos + 4) ;4 = {SOD} length -1 EndIf ; The packet is valid, strip its header {SOD}. $sPacket = StringTrimLeft($sPacket, 5) ; If the client hasn't sent who he is. If($_aClient[$i][$_iClientSubIdx_ComputerName] = "") Then ; Retreive the IP Address of the client to add it to the log and replace it the whois info. $sIPAddress = _GUICtrlListView_GetItemText($_hLwClient, $i) _GUICtrlListView_SetItemText($_hLwClient, $i, $sPacket) ; Assign the whois info. $_aClient[$i][$_iClientSubIdx_ComputerName] = $sPacket ; Assign the log file handle. $_aClient[$i][$_iClientSubIdx_FileHandle] = FileOpen($_sLogsDir & "\" & _WindowsFileName($sPacket) & ".log", $FO_APPEND) ; Write in the log the connected infos. FileWriteLine($_aClient[$i][$_iClientSubIdx_FileHandle], @CRLF & "Client connected " & _StringRepeat("#", 64 - 17) & @CRLF & "IP Address: " & $sIPAddress & @CRLF) Else ; Write into the log the data received. FileWrite($_aClient[$i][$_iClientSubIdx_FileHandle], $sPacket) EndIf ; If the client is the client showed by the log GUI. If $i = $_iLastClientLog Then ; Note: The maximum data length of an edit is 32767, we will ensure that it never exceeds this limit. ; Increment the log length displayed with the data received. $_aClient[$i][$_iClientSubIdx_LogLen] += StringLen($sPacket) ; If the log length displayed is upper 30000. If $_aClient[$i][$_iClientSubIdx_LogLen] > 30000 Then ; Trim the first 50 lines of the displayed log. $sLogRead = GUICtrlRead($_iEditLog) $iPos = StringInStr($sLogRead, @CRLF, 2, 50) + 1 ;$STR_NOCASESENSEBASIC ; Substrarct the 50 lines length from the displayed length. $_aClient[$i][$_iClientSubIdx_LogLen] -= $iPos ; Substract the data and apply it to the edit. GUICtrlSetData($_iEditLog, StringTrimLeft($sLogRead, $iPos)) EndIf ; Append the data received. _GUICtrlEdit_AppendText(GUICtrlGetHandle($_iEditLog), $sPacket) EndIf Next WEnd ; Delete the GUI (and its child GUIs) and its controls. GUIDelete($_hGUIMain) $_iLastClientLog = -1 ; Disconnect all clients. For $i = 0 To $_iMaxClients - 1 If($_aClient[$i][$_iClientSubIdx_Socket] = "") Then ContinueLoop _Client_Disconnect($i) Next ; Close the Listening socket to allow afterward binds. ; While not closed, any other program can NOT bind to the same IP Address and Port. TCPCloseSocket($iListenSocket) EndFunc ;==>Example Func _Client_Disconnect($iClient) ; If the client is the client showed by the log GUI hide the log. If $iClient = $_iLastClientLog Then _GUILog_Hide() EndIf ; If the client has a log file handle (meaning whois info received), write the disconnected info and close the file. If($_aClient[$iClient][$_iClientSubIdx_FileHandle] <> "") Then FileWriteLine($_aClient[$iClient][$_iClientSubIdx_FileHandle], @CRLF & @CRLF & "Client disconnected " & _StringRepeat("#", 64 - 20) & @CRLF) FileClose($_aClient[$iClient][$_iClientSubIdx_FileHandle]) EndIf ; Close the client socket. TCPCloseSocket($_aClient[$iClient][$_iClientSubIdx_Socket]) ; Delete the client listview item. _GUICtrlListView_DeleteItem($_hLwClient, $_aClient[$iClient][$_iClientSubIdx_Item]) ; Decrement the listview item index of the above items. For $i2 = 0 To $_iMaxClients - 1 If $_aClient[$i2][$_iClientSubIdx_Item] > $_aClient[$iClient][$_iClientSubIdx_Item] Then $_aClient[$i2][$_iClientSubIdx_Item] -= 1 EndIf Next ; Clear the client resources. For $i2 = 0 To UBound($_aClient, 2) - 1 $_aClient[$iClient][$i2] = "" Next EndFunc ;==>_Client_Disconnect Func _GUILog_Hide() $_iLastClientLog = -1 GUISetState(@SW_HIDE, $_hGUILog) EndFunc ;==>_GUILog_Hide Func _Dummy_ContextMenu() Switch GUICtrlRead($_iDyContextMenu) Case $_CM_DISCONNECT Local $iSelItem = Number(_GUICtrlListView_GetSelectedIndices($_hLwClient)) For $iClient = 0 To $_iMaxClients - 1 If $_aClient[$iClient][$_iClientSubIdx_Item] = $iSelItem Then ExitLoop Next _Client_Disconnect($iClient) EndSwitch EndFunc ;==>_Dummy_ContextMenu Func WM_CONTEXTMENU($hWnd, $Msg, $wParam, $lParam) #forceref $hWnd, $Msg, $wParam, $lParam If $hWnd <> $_hGUIMain Then Return $GUI_RUNDEFMSG Local $aCurInfo = GUIGetCursorInfo($hWnd) If $aCurInfo[4] <> $_iLwClient Then Return $GUI_RUNDEFMSG Local $aHit = _GUICtrlListView_HitTest($wParam) If $aHit[0] = -1 Then Return $GUI_RUNDEFMSG _GUICtrlListView_SetItemSelected($wParam, $aHit[0]) Local $hMenu = 0, $iMenuID = 0 $hMenu = _GUICtrlMenu_CreatePopup() _GUICtrlMenu_AddMenuItem($hMenu, "Disconnect", $_CM_DISCONNECT) $iMenuID = _GUICtrlMenu_TrackPopupMenu($hMenu, $wParam, -1, -1, 1, 1, 3) If $iMenuID Then GUICtrlSendToDummy($_iDyContextMenu, $iMenuID) _GUICtrlMenu_DestroyMenu($hMenu) Return $GUI_RUNDEFMSG EndFunc ;==>WM_CONTEXTMENU Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam) #forceref $hWnd, $iMsg, $iwParam, $ilParam Local $iIDFrom = 0, $iCode = 0, $tNMHDR = 0 $tNMHDR = DllStructCreate($tagNMHDR, $ilParam) $iIDFrom = DllStructGetData($tNMHDR, "IDFrom") $iCode = DllStructGetData($tNMHDR, "Code") Local $tInfo = 0, $iItem = 0 Switch $iIDFrom Case $_iLwClient Switch $iCode Case $NM_CLICK $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam) $iItem = DllStructGetData($tInfo, "Item") If $iItem = -1 Then Return $GUI_RUNDEFMSG WinSetTitle($_hGUILog, "", "Log - " & $_aClient[$iItem][$_iClientSubIdx_ComputerName]) GUISetState(@SW_SHOW, $_hGUILog) GUICtrlSetData($_iEditLog, "") _GUICtrlEdit_AppendText($_hEditLog, FileRead($_sLogsDir & "\" & $_aClient[$iItem][$_iClientSubIdx_ComputerName] & ".log")) $_iLastClientLog = $iItem EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_NOTIFY Func _WindowsFileName($sFileName) Return StringRegExpReplace($sFileName, '[\/:*?"<>|]', "") EndFunc ;==>_WindowsFileName Func SocketToIP($iSocket) Local $tSockAddr = 0, $aRet = 0 $tSockAddr = DllStructCreate("short;ushort;uint;char[8]") $aRet = DllCall("Ws2_32.dll", "int", "getpeername", "int", $iSocket, "ptr", DllStructGetPtr($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 _Exit() Exit EndFunc ;==>_Exit Func OnAutoItExit() TCPShutdown() EndFunc ;==>OnAutoItExit _ Client: (taken from the TCPConnect helpfile example, I added three lines under the Added region) expandcollapse popup#include <MsgBoxConstants.au3> ; I am the client, start me after the server! (Start first the TCPAccept example script). Example() Func Example() TCPStartup() ; Start the TCP service. ; Register OnAutoItExit to be called when the script is closed. OnAutoItExitRegister("OnAutoItExit") ; Assign Local variables the loopback IP Address and the Port. Local $sIPAddress = @IPAddress1 ; This IP Address only works for testing on your own computer. Local $iPort = 65432 ; Port used for the connection. ; Assign a Local variable the socket and connect to a Listening socket with the IP Address and Port specified. Local $iSocket = TCPConnect($sIPAddress, $iPort) ; If an error occurred display the error code and return False. If @error Then ; The server is probably offline/port is not opened on the server. Local $iError = @error MsgBox(BitOR($MB_SYSTEMMODAL, $MB_ICONHAND), "", "Could not connect, Error code: " & $iError) Return False EndIf #region Added ; Send the whois info. TCPSend($iSocket, "{SOD}I am " & @ComputerName & "{EOD}") ; Send some data (replace the header/footer code if present). TCPSend($iSocket, "{SOD}" & StringReplace(StringReplace(FileRead(@ScriptFullPath), "{SOD}", "[SOD]"), "{EOD}", "[EOD]") & "{EOD}") Sleep(5000) #endregion ; Close the socket. TCPCloseSocket($iSocket) EndFunc ;==>Example Func OnAutoItExit() TCPShutdown() ; Close the TCP service. EndFunc ;==>OnAutoItExit Br, FireFox. Edited August 22, 2013 by FireFox Link to comment Share on other sites More sharing options...
binarydigit0101 Posted August 22, 2013 Author Share Posted August 22, 2013 thank you for your complex code, I thought you made a simple one . it is quite hard for me to understand all its features, because I am a beginner. by the way I can't still understand what permits you to process an action while you're listening to other client connections. is it the array or a background function? ehi ehi ehi, what is your name? Link to comment Share on other sites More sharing options...
FireFox Posted August 22, 2013 Share Posted August 22, 2013 (edited) Yes it's "quite complex", that's why I added comments by the way I can't still understand what permits you to process an action while you're listening to other client connections.is it the array or a background function?Array. Edited August 22, 2013 by FireFox Link to comment Share on other sites More sharing options...
binarydigit0101 Posted August 22, 2013 Author Share Posted August 22, 2013 I guess here the listening socket accepts a new connection and inserts it into the array: ; If a new client is connected. If $iSocket <> -1 Then For $i = 0 To $_iMaxClients - 1 If($_aClient[$i][$_iClientSubIdx_Socket] <> "") Then ContinueLoop GUICtrlCreateListViewItem(SocketToIP($iSocket) & "|" & _Now(), $_iLwClient) $_aClient[$i][$_iClientSubIdx_Item] = _GUICtrlListView_GetItemCount($_hLwClient) - 1 $_aClient[$i][$_iClientSubIdx_Socket] = $iSocket ExitLoop Next EndIf next it loops through connected clients it finds in the array: ; Loop through the connected clients. For $i = 0 To $_iMaxClients - 1 If($_aClient[$i][$_iClientSubIdx_Socket] = "") Then ContinueLoop ; Receive from the client a maximum of 4 KiB data. $vRecv = TCPRecv($_aClient[$i][$_iClientSubIdx_Socket], 4096) ; If an error occurred disconnect the client and process the next one. If @error Then _Client_Disconnect($i) ContinueLoop EndIf now, I can't understand how can the code add a new user to array if it is processing the last loop. ehi ehi ehi, what is your name? Link to comment Share on other sites More sharing options...
FireFox Posted August 22, 2013 Share Posted August 22, 2013 now, I can't understand how can the code add a new user to array if it is processing the last loop. Huh? There is no multi threading, because it's not possible in autoit. While 1 ; Accept new client. ; If new client add it to the client array. ; Loop through the connected clients and process the packets. ; Go back to the start of the loop. WEnd Link to comment Share on other sites More sharing options...
binarydigit0101 Posted August 22, 2013 Author Share Posted August 22, 2013 exactly! if the code is looping through clients (3rd point), how can it accept new connection (1st and 2nd points)? because I guess it is still busy! ehi ehi ehi, what is your name? Link to comment Share on other sites More sharing options...
FireFox Posted August 22, 2013 Share Posted August 22, 2013 I believe the client is accepted internally then with the TCPAccept function you get the socket of the new client. Link to comment Share on other sites More sharing options...
binarydigit0101 Posted August 22, 2013 Author Share Posted August 22, 2013 (edited) so, probably I understood. please wait. I'll try to search a bug into my code so multi clients will work also for me. alright!!! I checked it and I find what was wrong: you are right when you say it accepts many connections but it will manage them one by one. I mean: when a client will connect I think it is put into an array but when it sends or receives message, it needs to be the only served from the server, so you need to create a three way handshake: client request (tcpconnect), server answer (tcpsend) and flush start of client (tcprecv for answer and others for communication). thank you so much hear you soon Edited August 22, 2013 by binarydigit0101 ehi ehi ehi, what is your name? Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now