Jump to content

TCP error when receiving data


Go to solution Solved by ripdad,

Recommended Posts

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?

Link to comment
Share on other sites

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

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

  • Solution

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

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

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...