Jump to content

SlowCoder74

Active Members
  • Posts

    178
  • Joined

  • Last visited

  • Days Won

    1

Everything posted by SlowCoder74

  1. I've been having performance difficulties with my TCP UDF. The more clients, the slower (almost exponentially) the communications. I set AutoItSetOption("TCPTimeout",0), and now the communications speed is almost instant between server and clients. The description of TCPTimeout is that it sets the ms for TCP functions to wait to receive data. It doesn't say anything about error management. Exactly what does it do? Does setting it to 0 have any mitigating issues?
  2. Thank you, dragan. I've run into this issue multiple times in the past, on various AutoIt programs I've written. Registering WM_COMMAND is the general response. But I'd really like to know why the "normal" method doesn't always work.
  3. I'm building my own TCP client/server UDF. It works, except for some reason it seems like GUI events are skipped in the main program loop. This is causing it to take multiple seconds (sometimes > 5) to send simple TCP data from server to clients. I have attached my UDF, and server and client source. The issue appears in the server program: - For testing, a pipe is written to console to show each iteration of the main loop. - When something is sent from the server, it writes the socket it is sending to into the console. Note that it displays it BEFORE actually calling the _TCPServer_SendData function, so I'm sure that function is not to blame. - If you run the server, and at least 1 client, when you click the Send button on the server, you can see that multiple iterations of the main loop happen (watch the pipes) before the GUI event is triggered. - Might be something in _TCPServer_CheckForNewConnections. If I remark that line in the main loop, the loop runs faster, and it seems like GUI events are captured. Help appreciated. Routines_TCP.au3 TCP Server.au3 TCP Client.au3
  4. I've been building a TCP server/client UDP and was balked by this very issue. Thanks to ripdad for pointing me to this thread. I concur with his statements about the illogical use of @error to indicate no data received. So that I can document in my code, and so that I am sure of the issue, we are effectively reverting the @error codes to 0 (like in older versions of AutoIt) if no data received, but setting @extended to -1 in the next stable release of AutoIt? What will the stable version number be?
  5. Ah, and that explains it. The help file is out of date, which only created confusion for me. I understand, as these guys are busy updating AutoIt, and sometimes things slip through the cracks. Don't know why they set @error = -1 if there's no data. That seems to go against logic. Why not just keep @error = 0 and return ""? ... Unless they're trying to account for null or something? I understand your finite looping. It would help mitigate a steady stream of data, and more or less equalize communications between clients.
  6. I added your code. Had to modify the elseif part to move the ExitLoop statement to Else. Otherwise it was stuck in a loop. No biggie. @error always returns -1, which, I guess is an unknown error. I found that just ignoring the -1 error seems to be the best method I've found. This is the version of the _TCPServer_ReceiveData function that seems to work: Func _TCPServer_ReceiveData($iClientSocket) ;retrieve any new data from all connected clients and add to each clients' data queue $iConn = _TCPServer_GetElemFromSocket($iClientSocket) If $aTCPClientState[$iConn] = "CONNECTED" Then Local $nError, $sReceivedData Do $sReceivedData = TCPRecv($iClientSocket, 128) $nError = @error Switch $nError Case 0 ;no error. process normally if $sReceivedData <> "" Then $aTCPClientReceivedData[$iConn] = $aTCPClientReceivedData[$iConn] & $sReceivedData ;MsgBox(0,"TCPServer - Received",$sReceivedData) EndIf Case -1 ;unknown error? doesn't seem to actually disconnect. appears the error can just be ignored. ;MsgBox(0, "TCPServer - Receive Error - NULL", $nError) $sReceivedData = "" Case Else ;MsgBox(0, "TCPServer - Receive Error", $nError) _TCPServer_Disconnect($iClientSocket) $sReceivedData = "" EndSwitch Until $sReceivedData = "" EndIf EndFunc
  7. Server code: Global $sTCPIPAddress = "127.0.0.1",$iTCPPort = "54321",$iTCPMaxConnections = 5 Global $iListenSocket = 0 Func _TCPServer_Initialize() OnAutoItExitRegister("OnAutoItExit") TCPStartup() ;initialize arrays to hold connection data Global $iTotalConnectedClients = 0 Global $aTCPClientState[$iTCPMaxConnections],$aTCPClientSocket[$iTCPMaxConnections] Global $aTCPClientIP[$iTCPMaxConnections],$aTCPClientPort[$iTCPMaxConnections] Global $aTCPClientReceivedData[$iTCPMaxConnections] for $iConn = 0 to $iTCPMaxConnections - 1 $aTCPClientState[$iConn] = "" $aTCPClientSocket[$iConn] = 0 $aTCPClientIP[$iConn] = "" $aTCPClientPort[$iConn] = 0 $aTCPClientReceivedData[$iConn] = "" next EndFunc Func _TCPServer_StartListen($sIPAddress,$iPort,$iMaxConnections = 10) ;open TCP port for listening $iSocket = TCPListen($sIPAddress, $iPort, $iMaxConnections) if @error Then return 0 Return $iSocket EndFunc Func _TCPServer_StopListen($iListenSocket) ;stop listening for new connections TCPCloseSocket($iListenSocket) EndFunc Func _TCPServer_CheckForNewConnections($iListenSocket) ;check for any new connections Do $iNewSocket = TCPAccept($iListenSocket) if $iNewSocket <> -1 Then ;add to connection list for $iConn = 0 to $iTCPMaxConnections - 1 if $aTCPClientState[$iConn] = "" Then $aTCPClientState[$iConn] = "CONNECTED" $aTCPClientSocket[$iConn] = $iNewSocket $iTotalConnectedClients = $iTotalConnectedClients + 1 ExitLoop EndIf Next EndIf Until $iNewSocket = -1 or $iTotalConnectedClients = $iTCPMaxConnections EndFunc Func _TCPServer_ReceiveData($iClientSocket) ;retrieve any new data from all connected clients and add to each clients' data queue $iConn = _TCPServer_GetElemFromSocket($iClientSocket) if $aTCPClientState[$iConn] = "CONNECTED" Then local $sReceivedData = TCPRecv(Int($iClientSocket),128) if @error then msgbox(0,"TCPServer - Receive Error",@error) _TCPServer_Disconnect($iClientSocket) Else if $sReceivedData <> "" Then $aTCPClientReceivedData[$iConn] = $aTCPClientReceivedData[$iConn] & $sReceivedData EndIf EndIf EndFunc Func _TCPServer_GetNextPacket($iClientSocket) ;parse client data queue and retrieve next packet $iConn = _TCPServer_GetElemFromSocket($iClientSocket) if StringInStr($aTCPClientReceivedData[$iConn],"[ENDPACKET]") > 0 Then Local $sPacket = StringLeft($aTCPClientReceivedData[$iConn],StringInStr($aTCPClientReceivedData[$iConn],"[ENDPACKET]") - 1) $aTCPClientReceivedData[$iConn] = StringRight($aTCPClientReceivedData[$iConn],StringLen($aTCPClientReceivedData[$iConn]) - (StringLen($sPacket + "[ENDPACKET]"))) Return $sPacket EndIf EndFunc Func _TCPServer_Disconnect($iClientSocket = 0) ;disconnect client(s), and reset values msgbox(0,"TCPServer","Disconnected") for $iConn = 0 to $iTCPMaxConnections - 1 if $iClientSocket = 0 or $aTCPClientSocket[$iConn] = $iClientSocket Then TCPCloseSocket($iClientSocket) ;reset socket specific values if $aTCPClientSocket[$iConn] <> 0 then $iTotalConnectedClients = $iTotalConnectedClients - 1 $aTCPClientState[$iConn] = "" $aTCPClientSocket[$iConn] = 0 $aTCPClientIP[$iConn] = "" $aTCPClientPort[$iConn] = 0 $aTCPClientReceivedData[$iConn] = "" EndIf next EndFunc Func OnAutoItExit() ;shut down TCP when application is closed _TCPServer_StopListen($iListenSocket) TCPShutdown() EndFunc Func _TCPServer_GetElemFromSocket($iClientSocket) ;return array element for given client socket for $iConn = 0 to $iTCPMaxConnections - 1 if $aTCPClientSocket[$iConn] = $iClientSocket Then Return $iConn EndIf next EndFunc #include <EditConstants.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> _TCPServer_Initialize() $iListenSocket = _TCPServer_StartListen($sTCPIPAddress,$iTCPPort) #Region ### START Koda GUI section ### Form= $Form1 = GUICreate("Form1", 256, 167, -1, -1) $Input1 = GUICtrlCreateInput("Input1", 8, 8, 57, 21) GUISetState(@SW_SHOW) #EndRegion ### END Koda GUI section ### While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE Exit EndSwitch ;check for new connections _TCPServer_CheckForNewConnections($iListenSocket) GUICtrlSetData($Input1,$iTotalConnectedClients) ;check for new received data for $iConn = 0 to $iTCPMaxConnections - 1 if $aTCPClientState[$iConn] = "CONNECTED" Then _TCPServer_ReceiveData($aTCPClientSocket[$iConn]) Next ;process new packets for $iConn = 0 to $iTCPMaxConnections - 1 $sReceivedData = "" if $aTCPClientState[$iConn] = "CONNECTED" Then $sReceivedData = _TCPServer_GetNextPacket($aTCPClientSocket[$iConn]) if $sReceivedData <> "" then msgbox(0,"",$sReceivedData) EndIf Next sleep(50) WEnd Client code: Global $sTCPServerIPAddress = "127.0.0.1",$iTCPServerPort = "54321" Global $iServerSocket = 0,$sConnState = "" Func _TCPClient_Initialize() OnAutoItExitRegister("OnAutoItExit") TCPStartup() EndFunc Func _TCPClient_Connect($sIPAddress,$iPort) $iServerSocket = TCPConnect($sIPAddress,$iPort) if $iServerSocket <> -1 Then $sConnState = "CONNECTED" Return 1 Else _TCPClient_Disconnect() Return 0 EndIf EndFunc Func _TCPClient_Send($sDataToSend) if $sConnState = "CONNECTED" Then TCPSend($iServerSocket,$sDataToSend + "[ENDPACKET]") if @error Then _TCPClient_Disconnect() EndIf EndFunc Func _TCPClient_Disconnect() TCPCloseSocket($iServerSocket) $sConnState = "" $iServerSocket = 0 EndFunc Func OnAutoItExit() _TCPClient_Disconnect() TCPShutdown() EndFunc #include <ButtonConstants.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> _TCPClient_Initialize() #Region ### START Koda GUI section ### Form= $Form1 = GUICreate("Form1", 238, 134, -1, -1) $Button1 = GUICtrlCreateButton("Connect", 8, 8, 89, 25) $Button2 = GUICtrlCreateButton("Disconnect", 8, 40, 89, 25) $Input1 = GUICtrlCreateInput("Input1", 8, 72, 113, 21) $Input2 = GUICtrlCreateInput("Input2", 8, 96, 105, 21) $Button3 = GUICtrlCreateButton("Send", 120, 96, 49, 25) GUISetState(@SW_SHOW) #EndRegion ### END Koda GUI section ### While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE Exit Case $Button1 _TCPClient_Connect($sTCPServerIPAddress,$iTCPServerPort) case $Button2 _TCPClient_Disconnect() case $Button3 _TCPClient_Send(GUICtrlRead($Input2)) EndSwitch GUICtrlSetData($Input1,$sConnState) sleep(50) WEnd These are quick/dirty TCP server/client code. I'm building the server to handle multiple simultaneous and continuous client connections. When I run both of these together, netstat indicates the client is successfully connected to the server: TCP 127.0.0.1:54321 0.0.0.0:0 LISTENING TCP 127.0.0.1:54321 127.0.0.1:65519 ESTABLISHED As soon as the server attempts to TCPRecv data from connected clients, it throws error and disconnects the client. The error happens in the _TCPServer_ReceiveData function, line 56, when it attempts to TCPRecv. I have verified that it appears to be using the correct and connected socket. Before I shoot my computer, please tell me why the code is breaking?
  8. I am also learning C#. I found http://www.csharp-station.com/tutorial.aspx, which helped me very much. Also, look up Patrick WashingtonDC's "C# programming tutorial - Step by Step" on youtube. I thought he did an excellent job explaining. Interestingly, I see many similarities between C# and AutoIt. Though the syntax of AutoIt isn't the same as C#, it is obvious that many of the concepts and keywords are shared from C# (or maybe C++?). If you're already familiar with AutoIt, it helps your learning curve a bit.
  9. You know ... I knew that. Dang it.
  10. Not sure what's going on here. I'm passing the hWnd of the previously created IE window to _IEAttach, but it doesn't seem to want to return the object so I can grab body text. IEAttach returns error 7 (no match). My sample script: #include <IE.au3> $iIEHWnd = Run(@ProgramFilesDir & "\Internet Explorer\iexplore.exe") sleep(5000) ;give time to finish loading page $oIE = _IEAttach($iIEHWnd,"hwnd") msgbox(0,"","Error:" & @error) $sIEBody = _IEBodyReadText($oIE) msgbox(0,"",$sIEBody)
  11. Yeah ... While for some reason it's not working in my code, the reproduced code appears to work ok. Therefore I'm gonna assume something else is broken. Will keep tinkering. Thanks, Melba.
  12. I seem to be finding that Opt("GUIResizeMode",$GUI_DOCKALL) doesn't work as I'd expect it. I would have assumed that this option would cause the default of all created window controls to be $GUI_DOCKALL (no moving). What I've found is that I still have to use GUICtrlSetResizing($hwnd, $GUI_DOCKALL) to all of the controls on my windows, individually. Otherwise they move when the window size is changed. Am I using it incorrectly?
  13. Ah, so when is there a "really good reason" to use OnEvent?
  14. Message Loop - This is the default method that AutoIT uses, similar to C-style languages. Involves including the message capture into the main loop. Event Driven - VB style. The main loop can process whatever (or nothing). When an event is generated, the appropriate function is called to handle the event. What are the benefits to using each of these modes? Speed? Code flow?
  15. BrewManNH, I went ahead and tried what you suggested on another part of the project, (separate program), and now see what you are explaining. It was easy to code. Thank you.
  16. I figured that question was coming. This is a multi-form project. example (main form): #include <ButtonConstants.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #Region ### START Koda GUI section ### Form= $Form2 = GUICreate("Form2", 180, 120, 345, 935) $Button1 = GUICtrlCreateButton("Button1", 8, 8, 97, 25) GUISetState(@SW_SHOW) #EndRegion ### END Koda GUI section ### While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE Exit case $Button1 #include "myincludeforbutton1.au3" EndSwitch WEnd myincludeforbutton1.au3 (2nd level form): ... form drawing code ... ... 2nd loop to handle 2nd form messages, etc ... Due to the size of project code, and in attempt to keep myself sane, I've split the code into multiple includes. The includes contain the form creation and loops for each new form/window. Unfortunately, I cannot create a function within one of the includes, because procedurally, they are inside at least one loop (switch). To create a function, I would need to put it in the 1st level code file. This makes the code feel disorganized. It's not that it couldn't work, but I want to prevent it if I can.
  17. Well, I wasn't trying to actually click the combobox. I know ControlClick isn't what I wanted to do. I want to create a GUI message so that it's picked up by GUIGetMsg as if the combobox value has been changed. If you're familiar with VB, an event procedure is created for a control object, e.g. MyControl_Click, that would fire when you clicked the MyControl control. Or you could simply call it as a sub from code. I need to see if I can get a solution that does not require the building of a separate function. Any other options?
  18. Sample code: #include <ButtonConstants.au3> #include <ComboConstants.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #Region ### START Koda GUI section ### Form= $Form2 = GUICreate("Form2", 405, 284, 343, 1121) $Combo1 = GUICtrlCreateCombo("", 24, 8, 113, 25, BitOR($CBS_DROPDOWNLIST,$CBS_AUTOHSCROLL)) GUICtrlSetData(-1, "Item1|Item2") $Button1 = GUICtrlCreateButton("Simulate", 24, 40, 65, 25) GUISetState(@SW_SHOW) #EndRegion ### END Koda GUI section ### While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE Exit Case $Combo1 msgbox(0,"","Selection changed!") Case $Button1 ;simulate combobox selection change ControlClick($Form2,"",$Combo1) EndSwitch WEnd My desired outcome is to simulate a click on the combobox so that a gui message is sent and the messagebox appears. What actually happens is that the combobox drops down. I don't want to have to create a separate function that needs to be called from each point in the code, if I can help it.
  19. Yep, I understood that, and that was what my response was for.
  20. They are R/O, not R/W, and do have error correction built in just in case the file is locked. But the issue was actually unrelated to file accesses.
  21. I guess I'll put it this way. The positions and sizes are calculated dynamically during creation, based on the number of agents, text size, etc. I did not consciously decide the specific locations of each, other than to build the calculation algorithm. So, yes, the locations are "known", but not necessarily stored in any variables within my app. After the labels have been created, sized and placed, only the text and colors have to be updated as the new wallboard information is retrieved. If you're interested, I've attached an image of the wallboard. The columns and rows can be configured, as well as font, font size, etc. Everything is dynamic.
  22. No, I don't specifically know the positions, because they are dynamically created based on a number of agents, rows, columns, etc. Removing WinGetTitle seems to have fixed it! I'm sure I had a great reason for putting it in there in the beginning. Maybe ControlGetPos didn't support just using hWnd when I wrote the function? I dunno.
  23. As explained before, in another thread, I am developing a wallboard, which contains many labels (up to 384) that are dynamically created. I may run multiple instances of the EXE at one time. It seems if I run instance 1, and while it is creating the labels I run instance 2/3/4, the labels in the other instances are not created correctly. A subsequent reload of the other instances allows them to load correctly. It's as if they are sharing a master process (they aren't, in my code), or there is leakage of data. I think I've tracked it down to a call to ControlGetPos(), which doesn't always seem to return an array of data. At first thought, you'd think maybe the window or label hWnd were invalid, but then a simple addition of a conditional loop around the ControlGetPos() func until it returns an array: $ControlParams="" while not IsArray($ControlParams) $ControlParams=ControlGetPos(WinGetTitle($FrmHWnd),"",$LabelHwnd) wend partially fixes the problem, and there are no errors. At this point, it's like we're waiting for the label to actually be created. But still the function doesn't seem to return the proper parameters, as the label is then not properly repositioned with the following command: $VPadding=1 GUICtrlSetPos($LabelhWnd,Default,Default,Default,$ControlParams[3]+($VPadding*2)) Here is my full function: #include "_StringSize.au3" ;supplied by Melba23 Func _CreateLabel($FrmHWnd,$Txt,$X,$Y,$W=-1,$H=-1,$VPadding=0,$FontSize="10",$FontFace="Times New Roman",$Style="BOLD",$Align="LEFT",$FGColor="777777",$BGColor="000000") ;Creates label based on provided parameters, and returns the hWnd of the label control ;$FrmHWnd=control ID of form to add label to ;$Txt=text to display ;X=left,Y=top ;W=[width],H=[height]. If either is omitted, that parameter is variable. Otherwise, static ;$VPadding=[vertical padding] ;$FontSize=fontsize,$FontFace=[fontface] ;$Style=[NORMAL,BOLD,ITALIC,UNDERLINE,STRIKE] ;$Align=[LEFT,RIGHT,HCENTER,VCENTER] ; Note: using VCENTER seems to disable multiline support in the labels ;$FGColor=[RRGGBB],$BGColor=[RRGGBB] ;convert RGB HTML (#) to RGB Hex (0x) colors $FGColor = _RGBColor($FGColor,"0x") $BGColor = _RGBColor($BGColor,"0x") ;set default values if $X="" then $X=0 ;left if $Y="" then $Y=0 ;top if $W="" then $W=-1 ;width if $H="" then $H=-1 ;height if $VPadding="" then $VPadding=0 ;get styles $FontStyle=0 if StringInStr($Style,"ITALIC",0) > 0 then $FontStyle = $FontStyle + 2 if StringInStr($Style,"UNDERLINE",0) > 0 then $FontStyle = $FontStyle + 4 if StringInStr($Style,"STRIKE",0) > 0 then $FontStyle = $FontStyle + 8 $FontWeight=400 ;default font weight if StringInStr($Style,"BOLD",0) > 0 then $FontWeight = 800 ;get alignment $AlignMode=$GUI_SS_DEFAULT_LABEL if StringInStr($Align,"LEFT",0) > 0 then $AlignMode = BitOR($AlignMode,$SS_LEFT) if StringInStr($Align,"HCENTER",0) > 0 then $AlignMode = BitOR($AlignMode,$SS_CENTER) if StringInStr($Align,"RIGHT",0) > 0 then $AlignMode = BitOR($AlignMode,$SS_RIGHT) if StringInStr($Align,"VCENTER",0) > 0 then $AlignMode = BitOR($AlignMode,$SS_CENTERIMAGE) ;note: using VCENTER seems to disable multiline support in the labels ;determine label size $LabelParams=_StringSize($Txt,int($FontSize),int($FontWeight),$FontStyle,$FontFace) ;get required parameters to display label if $W=-1 then $W=$LabelParams[2] ;variable width, based on label if $H=-1 then $H=$LabelParams[3] ;variable height, based on label ;create label $LabelhWnd=GUICtrlCreateLabel($Txt,$X,$Y,$W,$H,$AlignMode) ;create label GUICtrlSetFont($LabelhWnd,$FontSize,$FontWeight,$FontStyle,$FontFace) ;adjust font if $FGColor<>"" then GUICtrlSetColor($LabelhWnd, $FGColor) ;foreground color if $BGColor<>"" then GUICtrlSetBkColor($LabelhWnd, $BGColor) ;background color. If "", will be transparent ;add vertical padding if IsNumber($VPadding) and $VPadding<>"" Then $ControlParams = "" while Not IsArray($ControlParams) $ControlParams=ControlGetPos(WinGetTitle($FrmHWnd),"",$LabelHwnd) WEnd GUICtrlSetPos($LabelhWnd,Default,Default,Default,$ControlParams[3]+($VPadding*2)) EndIf Return $LabelhWnd EndFunc (Sorry, looks like indentation got a little screwed up)
  24. This helped greatly! I have now determined the location of my error through testing. Now to figure out why ControlGetPos sometimes doesn't return proper information (another thread)!
  25. I've got this pesky error on my wallboards, that I believe may be caused by a file multi-access issue. However, it difficult to determine exactly where the error is, as it only appears in the compiled EXE. The wallboard is designed to reload (re-run itself, then exit) upon detection of a change in the configuration file. There can be multiple instances of the wallboard EXE running, either on the same PC, or on multiple PCs, all accessing the same config file and data. Upon reload, any number of the wallboard instances may fail, usually leaving only one instance running. I can't test this uncompiled, as the wallboard can't re-run its own uncompiled code. I know the EXE actually contains the AU3 code in its full glory (that's what I understand, anyway). From the error I'm getting, is there a way to determine which line corresponds to the error, and is actually causing the problem? The error is: Like, can I say "just substract 6500 from 7849 to get the actual line"?
×
×
  • Create New...