Gianni Posted April 10, 2013 Share Posted April 10, 2013 hello, If i use TCPRecv($Socket, 2048) but TCPSend() transmit more than 2048 bytes, i lose data. Is there a way to know when the TCPRecv() command has no more data to read from a single TCPSend()? for example, I wonder if there's a way similar to that of reading the output of a dos command ? ; read all the output of a dos command $iPID = Run('"' & @ComSpec & '" /c ' & $sCommand, "", @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD) While 1 $sOutput &= StdoutRead($iPID, False, False) If @error Then ; <--- no more data to read <--- ExitLoop EndIf Sleep(10) WEnd thanks 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...
JohnOne Posted April 10, 2013 Share Posted April 10, 2013 What happened when you tried the example in the help file? AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans. Link to comment Share on other sites More sharing options...
Gianni Posted April 10, 2013 Author Share Posted April 10, 2013 thanks JohnOnemy problem is that if I receive a "message" longer than 2048, I lose the final part of the "message"(of course I do not want to increase the number 2048 in the command TCPRecv ())what I try to do is a server that receives dos commands from one or more clients, executes them and returns the result to the client.inserting a DOS command in the upper section of the GUI and clicking on the button, you will receive the result of the command that is executed by the server, and displayed in the lower box.if I enter dos commands that produce a shorter output (eg ipconfig), there are no problems, but if I enter a command with a long output (eg dir c:\ /s) then I will lose part of the output.the server:expandcollapse popup; this server script will receive and execute dos commands from a remote client ; and return the result to the caller client #include <Array.au3> #include <Constants.au3> TCPStartup() ; Init TCP/IP Dim $Socket_Data[1] ; will hold track of incomming clients $Socket_Data[0] = 0 ; start with 0 clients connected $Listen = TCPListen(@IPAddress1, 9057, 5) If @error Then ConsoleWrite('!--> TCPListen error number ( ' & @error & ' ).' & @CRLF) TCPShutdown() Exit ; --> End due to an error. EndIf While 1 For $x = $Socket_Data[0] To 1 Step -1 ; scans all connected clients $Recv = TCPRecv($Socket_Data[$x], 2048) ; check if there is data to read If $Recv Then ; If we received something, the $Recv variable will hold that data. Switch $Recv ; analyze incoming messages Case "kill server" ; stop all connections and exit for $x0 = $Socket_Data[0] To 1 Step -1 TCPSend($Socket_Data[$x0], "Server killed" & @CRLF) ; notify to client Sleep(2000) TCPRecv($Socket_Data[$x0], 512) TCPCloseSocket($Socket_Data[$x0]) ; disconnect client Next TCPShutdown() Exit ; the end Case "bye" ; disconnect only this client TCPSend($Socket_Data[$x], "bye bye client " & _SocketToIP($Socket_Data[$x])) TCPCloseSocket($Socket_Data[$x]) _ArrayDelete($Socket_Data, $x) ; delete client from array $Socket_Data[0] -= 1 Case Else ; run the dos command and returns the result to the client that requested it TCPSend($Socket_Data[$x],_GetDOSOutput($Recv)) EndSwitch EndIf Next _Accept() ; _Accept will check for new connections so we will call it once on every loop. WEnd ; ========================== ; Functions zone ; ========================== Func _Accept() Local $Accept = TCPAccept($Listen) ; are there new connection requests ? If $Accept <> -1 Then _ArrayAdd($Socket_Data, $Accept) $Socket_Data[0] += 1 EndIf EndFunc ;==>_Accept Func _GetDOSOutput($sCommand) ; run the dos command and returns the result Local $iPID, $sOutput = "" $iPID = Run('"' & @ComSpec & '" /c ' & $sCommand, "", @SW_HIDE, $STDERR_MERGED) ; $STDERR_CHILD + $STDOUT_CHILD) While 1 $sOutput &= StdoutRead($iPID, False, False) If @error Then ExitLoop EndIf Sleep(10) WEnd Return $sOutput EndFunc ;==>_GetDOSOutput ; Function to return IP Address from a connected socket. ;---------------------------------------------------------------------- Func _SocketToIP($SHOCKET) Local $sockaddr, $aRet $sockaddr = DllStructCreate("short;ushort;uint;char[8]") $aRet = DllCall("Ws2_32.dll", "int", "getpeername", "int", $SHOCKET, _ "ptr", DllStructGetPtr($sockaddr), "int*", DllStructGetSize($sockaddr)) If Not @error And $aRet[0] = 0 Then $aRet = DllCall("Ws2_32.dll", "str", "inet_ntoa", "int", DllStructGetData($sockaddr, 3)) If Not @error Then $aRet = $aRet[0] Else $aRet = 0 EndIf $sockaddr = 0 Return $aRet EndFunc ;==>_SocketToIPthe clientexpandcollapse popup#include <ButtonConstants.au3> #include <EditConstants.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #Region ### START Koda GUI section ### Form= $Form1 = GUICreate("Form1", 623, 323, 280, 165) $Edit1 = GUICtrlCreateEdit("", 8, 8, 593, 113) GUICtrlSetData(-1, "Edit1") $Edit2 = GUICtrlCreateEdit("", 8, 184, 593, 129) GUICtrlSetData(-1, "Edit2") $Button1 = GUICtrlCreateButton("Button1", 8, 128, 593, 17) GUISetState(@SW_SHOW) #EndRegion ### END Koda GUI section ### TCPStartup() Local $g_IP = @IPAddress1 ; same as server this example While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE Exit Case $Button1 $Socket = TCPConnect($g_IP, 9057) ; call the server If @error Then ConsoleWrite('!--> TCPConnect error number ( ' & @error & ' ).' & @CRLF) Exit EndIf ; ConsoleWrite(GUICtrlRead($Edit1) & @CRLF); echo on console TCPSend($Socket, GUICtrlRead($Edit1)) ; send the content of upper Edit1 Do ; wait for answer from server $Recv = TCPRecv($Socket, 2048) ; <- HERE LOST OF DATA <--- ; ConsoleWrite(".") Until $Recv GUICtrlSetData($Edit2,$Recv) ; write the result from server to Edit2 ; ConsoleWrite(@CRLF & $Recv & @CRLF) ; echo on console EndSwitch WEndP.S.I wrote these scripts by modifying the examples in this tutorial:thanks 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...
JohnOne Posted April 11, 2013 Share Posted April 11, 2013 If you look at the example in the help file you will see it loops tcprecv until @error, meaning there is no data left to reeieve. AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans. Link to comment Share on other sites More sharing options...
Gianni Posted April 11, 2013 Author Share Posted April 11, 2013 you mean this part of the help file?; ; While 1 $msg = GUIGetMsg() ; GUI Closed ;-------------------- If $msg = $GUI_EVENT_CLOSE Then ExitLoop ; Try to receive (up to) 2048 bytes ;---------------------------------------------------------------- $recv = TCPRecv($ConnectedSocket, 2048) ; If the receive failed with @error then the socket has disconnected ;---------------------------------------------------------------- If @error Then ExitLoop ; convert from UTF-8 to AutoIt native UTF-16 $recv = BinaryToString($recv, 4) ; Update the edit control with what we have received ;---------------------------------------------------------------- If $recv <> "" Then GUICtrlSetData($edit, _ $szIP_Accepted & " > " & $recv & @CRLF & GUICtrlRead($edit)) WEnd I think this @ error occurs only if the client disconnects, or am I wrong? 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...
sentry07 Posted April 11, 2013 Share Posted April 11, 2013 I use a large receive buffer size (32000) so that I know I will receive everything that's being sent. I believe data will sit in the receive buffer until you call TCPRecv. If there's more data in the buffer than your TCPRecv is requesting, then it will leave the excess data in the buffer until the next time you call TCPRecv. I guess you could do a While loop until TCPRecv returns nothing every time and just append the received data to a string. Link to comment Share on other sites More sharing options...
Gianni Posted April 11, 2013 Author Share Posted April 11, 2013 hello sentry07, thanks for your suggestion maybe, like you say, read the data with TCPRecv () until it receives a null string can fit. I do not know if it's the best way, but this way it works. (...who knows if a delay on the network could result in an empty string even if there is data to be received?...) this is the reading loop that works. TCPSend($Socket, GUICtrlRead($Edit1)) ; send the request to server Do ; wait for answer from server $RecvBuffer = TCPRecv($Socket, 2048) ; first part of receiving data goes in $RecvBuffer sleep(100) Until $RecvBuffer ; stay here if nothing received yet While 1 ; read more dada if available $Recv = TCPRecv($Socket, 2048) ; is there more data ? if $Recv = "" then ; <--- if no more data to read then exit ExitLoop EndIf $RecvBuffer = $RecvBuffer & $Recv ; append new data to buffer Sleep(10) WEnd $Recv = $RecvBuffer ; complete output is in $Recv Bye and thanks again 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...
funkey Posted April 11, 2013 Share Posted April 11, 2013 (...who knows if a delay on the network could result in an empty string even if there is data to be received?...)Yes network timeout can result in receiving nothing. Sometimes you have to set the recv timeout of the connection. Programming today is a race between software engineers striving tobuild bigger and better idiot-proof programs, and the Universetrying to produce bigger and better idiots.So far, the Universe is winning. Link to comment Share on other sites More sharing options...
bogQ Posted April 12, 2013 Share Posted April 12, 2013 (edited) i did name it Third Part: Understanding for how is msg received on server but that don't mean you can't use it on client You need to know where msg starts and where msg ends, for example if server sends data but before it started sending data it put '#SS#'&and after he stop sending data he sends '*ES*' or something similar of your choice then you only need to check on client with split-string-betwean or something third. For example if stringinstr *ES* so that you know you recived some msg to the end and current data is ready to rejoin rest of msg with old data. Or you can check if string between returns array and you tell it then to split your string because you know you received msg from start to end and filter out msg that isn't complete so that you rejoin it next time on tcp receive dirty example: #include <String.au3> #include <Array.au3> ;small test ;~ $tcpstr = "#SS#Hi Im Stri" ;larger test $tcpstr = "#SS#Hi Im String1*ES*#SS#Hi Im String2*ES*#SS#Hi Im String3*ES*#SS#Hi Im String4*ES*#SS#Hi Im String5*ES*#SS#Hi Im Stri" If $tcpstr Then Local $aArray1 = _StringBetween($tcpstr, '#SS#', '*ES*') If IsArray($aArray1) Then Local $lenght = UBound($aArray1) - 1 For $x = 0 To $lenght $tcpstr = StringReplace($tcpstr, '#SS#' & $aArray1[$x] & '*ES*', '') Next _ArrayDisplay($aArray1, 'Recived nmbr: '&$lenght+1) If $tcpstr Then MsgBox(0, "Msg nmbr :"&$lenght+2&". Still w8ing to recive end on this msg", $tcpstr) ;rejoin it Else MsgBox(0, "Empty", 'no more msgs at the moment') EndIf Else MsgBox(0, "Still w8ing to recive end on this msg", $tcpstr) ;rejoin it EndIf Else MsgBox(0, "Empty", 'no more msgs at the moment') EndIf Edited April 12, 2013 by bogQ TCP server and client - Learning about TCP servers and clients connectionAu3 oIrrlicht - Irrlicht projectAu3impact - Another 3D DLL game engine for autoit. (3impact 3Drad related) There are those that believe that the perfect heist lies in the preparation.Some say that it’s all in the timing, seizing the right opportunity. Others even say it’s the ability to leave no trace behind, be a ghost. Link to comment Share on other sites More sharing options...
Gianni Posted April 12, 2013 Author Share Posted April 12, 2013 hello bogQ, thanks for your answer I understood the mechanism of precede with '# SS #' at the beginning and append '** ES **' at the end of each message, in this way I know exactly where it begins and where it ends any message,it is also possible to send multiple messages in a single TCPSend() I thought that TCPSend () would automatically add an EOF or EOT ascii character or something similar for each transmission, but evidently it is not so. I have to manage on my own traffic data. please, another question: when I do this close sequence on the server: TCPCloseSocket($Socket) TCPShutdown() Exit and then I control the active tasks on the computer I see that the myserver.exe task is still alive till I close also the client (after the close sequence myserver.exe it remain in the task list also if it do not give no more answers to client's call), in fact only when i close the client also the server disappear from the task list. is there a better way to shut down the server? thanks again P.S. I found your tutorials on tcpip very useful, clear and easy to follow. my compliments, nice work! 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...
bogQ Posted April 12, 2013 Share Posted April 12, 2013 (edited) I have some questionsare you shure you don't have something else in there that don't allow you to exit? did you try to put msgbox or consolewrite to see where it hangs or Opt("TrayIconDebug", 1)? Maybe some opened program or file with run command that strangely hangs autoit program.why do you sleep 2 sec after every TCPSend on server? if its to ensure that msg is received about server dccing there isn't any need, error check on client shud inform client that connection with the server is reseted. and why do you try to receive "TCPRecv($Socket_Data[$x0], 512)?" after that sleep if your already trying to disconnect client?I did try your script under win7 with 'kill server' uncompiled and compiled, it worked with no problem, server exited while client still stayed opened, and server did not hang in task manager. Edited April 12, 2013 by bogQ TCP server and client - Learning about TCP servers and clients connectionAu3 oIrrlicht - Irrlicht projectAu3impact - Another 3D DLL game engine for autoit. (3impact 3Drad related) There are those that believe that the perfect heist lies in the preparation.Some say that it’s all in the timing, seizing the right opportunity. Others even say it’s the ability to leave no trace behind, be a ghost. Link to comment Share on other sites More sharing options...
Gianni Posted April 12, 2013 Author Share Posted April 12, 2013 I have to make more test on the server shutdown because sometime it stop correctly sometime with a delay and sometime only after I turn off the client. ... I also compiled the server for x86 but I use it both on win xp x32 than on win7 x64, perhaps this fact can affect .... regarding the delays of 2 seconds and the TCPRecv ($ SOCKET_DATA [$ x0], 512), well, I do not know why they are used, really I asked the same question to myself when i've "blindly" ripped and adapted the closing sequence from the example script in the autoit help for the command TCPCloseSocket() this is the function from the example of the AutoIt Help for the command TCPCloseSocket : Func Cleanup() ;ON SCRIPT EXIT close opened sockets and shutdown TCP service ;---------------------------------------------------------------------- If $ConnectedSocket > -1 Then TCPSend($ConnectedSocket, "~~bye") Sleep(2000) TCPRecv($ConnectedSocket, 512) TCPCloseSocket($ConnectedSocket) EndIf TCPCloseSocket($MainSocket) TCPShutdown() EndFunc ;==>Cleanup 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...
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