SlowCoder74 Posted June 10, 2014 Share Posted June 10, 2014 Server code: expandcollapse popupGlobal $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: expandcollapse popupGlobal $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? Link to comment Share on other sites More sharing options...
ripdad Posted June 11, 2014 Share Posted June 11, 2014 If you are using a newer version of AutoIt, try this as a temporary solution...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 For $i = 1 To 100 $sReceivedData &= TCPRecv(Int($iClientSocket), 128) $nError = @error If Not StringRegExp($nError, '(-1|0)') Then MsgBox(0, "TCPServer - Receive Error", $nError) _TCPServer_Disconnect($iClientSocket) ExitLoop ElseIf $sReceivedData <> "" Then $aTCPClientReceivedData[$iConn] = $aTCPClientReceivedData[$iConn] & $sReceivedData Exitloop EndIf Sleep(10) Next EndIf EndFunc If you continue to have an error, please reply what the error code is. "The mediocre teacher tells. The Good teacher explains. The superior teacher demonstrates. The great teacher inspires." -William Arthur Ward Link to comment Share on other sites More sharing options...
SlowCoder74 Posted June 11, 2014 Author Share Posted June 11, 2014 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 Link to comment Share on other sites More sharing options...
Solution ripdad Posted June 11, 2014 Solution Share Posted June 11, 2014 As of v3.3.10.0: -1 = no bytes have been received. It's not an error. I have been talking to jpm about it here: '?do=embed' frameborder='0' data-embedContent>> The For loop 100 is my way of escaping the infinite, if something went wrong. Works fine for me - although some might prefer something else. "The mediocre teacher tells. The Good teacher explains. The superior teacher demonstrates. The great teacher inspires." -William Arthur Ward Link to comment Share on other sites More sharing options...
SlowCoder74 Posted June 12, 2014 Author Share Posted June 12, 2014 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. 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