Jump to content
ferbfletcher

TCPSend in loop eventually causes "program not responding"

Recommended Posts

ferbfletcher

If I do something like this, it works;

While 1

... do something to populate $mydata

TCPConnect($sIPAddress, $iPort)

TCPSend($iSocket, $mydata)

TCPCloseSocket($iSocket)

WEnd

However, if I do something like this, it hangs after awhile with "program not responding"

TCPConnect($sIPAddress, $iPort)

While 1

... do something to populate $mydata

TCPSend($iSocket, $mydata)

WEnd

TCPCloseSocket($iSocket)

The second method does not close the socket between every TCPSend, in order to keep the connection open/persistent.  Unfortunately, it seems that after a certain amount has been sent, the TCPSend function hangs forever.  No error returned, it just hangs without proceeding with the spinning cursor and the "not responding" windows message in the title.

Is there a maximum limit for keeping the connection open?  Is this a bug?

 

 

 

Edited by ferbfletcher

Share this post


Link to post
Share on other sites
RTFC

Are you clearing the TCP buffer as well, and sufficiently fast? To quote from StackOverflow:

Quote

TCP only allows a certain amount of data to remain unacknowledged at a time. If a server is producing data faster than a client is consuming data then the amount of data that is unacknowledged will increase until the TCP window is 'full' at this point the sending TCP stack will wait and will not send any more data until the client acknowledges some of the data that is pending.

 

Share this post


Link to post
Share on other sites
ferbfletcher
10 hours ago, AoRaToS said:

I use Do...Until for TCP file transfer, what kind of data are you sending?

I am constantly monitoring file contents and sending tcp data based on that.  So there is data being sent over the tcp socket all the time.  Not a lot of data, but a slow continual flow.

Share this post


Link to post
Share on other sites
ferbfletcher
10 hours ago, RTFC said:

Are you clearing the TCP buffer as well, and sufficiently fast? To quote from StackOverflow:

TCP only allows a certain amount of data to remain unacknowledged at a time. If a server is producing data faster than a client is consuming data then the amount of data that is unacknowledged will increase until the TCP window is 'full' at this point the sending TCP stack will wait and will not send any more data until the client acknowledges some of the data that is pending.

 

I don't think that AutoIT has a method to "clear the tcp buffer", or perhaps it is built into the TCPSend function.  Regardless, if that was an issue, I would expect @error to be returned from the TCPSend function.  Instead, the TCPSend function is never finishing, it simply hangs and you have to forcefully close the program.

In order for a function to hang forever (it was hung for 2 weeks before I noticed it) without returning an error, that seems like a bug within the function.  

Share this post


Link to post
Share on other sites
ripdad

ferbfletcher,

The code in your first post is not enough to determine what is going on with your script. Please post a "runnable" script with error checking.


"The mediocre teacher tells. The Good teacher explains. The superior teacher demonstrates. The great teacher inspires." -William Arthur Ward

Share this post


Link to post
Share on other sites
ferbfletcher

Ok, here is a working example that hangs every time:

SERVER CODE (This is not the actual server code, it's just so that the client below will actually run)  The server code is not an issue, and it does not hang.  Start the server BEFORE starting the client.  Run both of these programs on the same computer.

TCPStartup()
$iListenSocket = TCPListen("127.0.0.1", 500, 100)

Do
  $iSocket = TCPAccept($iListenSocket)
Until $iSocket <> -1 ;if different from -1 a client is connected.

while 1
  $sReceived = TCPRecv($iSocket,100)
  sleep(10)
WEnd

CLIENT CODE (This hangs every time, around iteration 328.  You will see the loop iteration increase by the mouse cursor).  Start this after starting the server.

TCPStartup()

$iSocket = TCPConnect("127.0.0.1", 500)
$x = 0
Local $mydata

;This is to make a realistically large amount of data for testing purposes
For $a = 1 to 100
  $mydata &= "xxxxxxxxxxxxxxxxxxxx"
Next

While 1
  $x += 1
  TCPSend($iSocket, $mydata)
  If @error <> 0 Then MsgBox(0,"Error",@error)
  ToolTip($x) ;this is for a visual indication of program running
  Sleep(10)
WEnd

 

Edited by ferbfletcher

Share this post


Link to post
Share on other sites
RTFC

You're sending two thousand bytes every 10 ms, and reading one hundred bytes at the other end at the same rate. How is that not eventually going to exceed your TCP buffer (default: 0x4470 bytes)?

Share this post


Link to post
Share on other sites
ripdad

ferbfletcher,

I have modified both scripts. The server code has been changed to a tried and true method that I have used for several years. It has never failed for me. The client code has a few changes in it, but I have no idea how you plan to implement it, since i'm not sure how you're using it. Please read my comments in the two codes. (not thoroughly tested)

Server:

TCPStartup()

Local $iListenSocket = TCPListen("127.0.0.1", 500, 100)
Local $iSocket, $sReceived

While 1
    Do
        Sleep(250)
        $iSocket = TCPAccept($iListenSocket)
    Until $iSocket > 0
    ;
    For $i = 1 To 200; <-- acts as a timeout (200 * 10ms sleep) - gives a way to escape an infinite loop
        $sReceived = TCPRecv($iSocket, 8192); <-- may need to adjust, but should be okay
        If @error Then
            ExitLoop; <-- exits the for loop
        ElseIf StringLen($sReceived) Then
             $i = 1; <-- reset for loop timer
            ; <-- do something with the received data
        EndIf
        Sleep(10)
    Next
    TCPCloseSocket($iSocket); <-- close the socket and go back to listen/accept/idle mode
WEnd

Client:

TCPStartup()

Local $iSocket = TCPConnect("127.0.0.1", 500)

Local $iError, $mydata = ''
Local $x = 0

;This is to make a realistically large amount of data for testing purposes
For $a = 1 To 100; <-- 2000 bytes of data
    $mydata &= "xxxxxxxxxxxxxxxxxxxx"
Next

While 1
    $x += 1
    TCPSend($iSocket, $mydata)
    $iError = @error
    If $iError Then
        MsgBox(0, "Error", $iError, 5); <-- 5 second timeout (will automatically close)
        ExitLoop; <-- once there is an error, the session has ended for this loop (a reset will be needed of some kind)
    EndIf
    ToolTip($x) ;this is for a visual indication of program running
    Sleep(10); <-- send 2000 bytes of data every 10 milliseconds???
WEnd

ToolTip('')
TCPCloseSocket($iSocket)
TCPShutDown()

 


"The mediocre teacher tells. The Good teacher explains. The superior teacher demonstrates. The great teacher inspires." -William Arthur Ward

Share this post


Link to post
Share on other sites
ripdad

ferbfletcher,

Also in my opinion, it's best not to leave a socket open for too long.
Sending data in time intervals is the best way.

So, if there is time delays between data chunks,
it's best to close the socket in between the delays.

Then reconnect and do it again. This way, everything is cut and dry.


"The mediocre teacher tells. The Good teacher explains. The superior teacher demonstrates. The great teacher inspires." -William Arthur Ward

Share this post


Link to post
Share on other sites
ferbfletcher

The actual server is not a script.  It is a proprietary linux server of some sort that accepts TCP input, but the identical thing happens with it, the autoit client hangs after some time... so the simple server script above is included just so that the client example will run.

I'm not actually sending that much data that quickly, that's just for the sample script to make the hang happen sooner so you don't have to run it a long time.

Regardless of the speed or amount of data or overflowing anything, the fact remains that tcpsend should NEVER hang.  Return an error... that's fine.  Lose data... that can be worked around.  Hang with NO errors... that's a bug in my opinion.

So... I'm curious, what are your thoughts on it hanging forever and not returning any errors?

 

 

 

 

Edited by ferbfletcher

Share this post


Link to post
Share on other sites
ferbfletcher

Even if I slow the client way down, like sleep(1000) instead of sleep(10), it still hangs at the exact same iteration every time .. so the speed isn't the issue.

Also, even if I decrease the data size (like to 1/10 of the size), it still hangs after the same amount of data has been sent.. you just have to wait longer for it to send that amount of data .. so it isn't the amount of data being sent at a time that is the issue.

Share this post


Link to post
Share on other sites
ripdad

Well, you got my curiosity motor running.

I ran the client script that I posted to the 7000 count.
So at this point, i don't know where the problem is.

Download this zipfile and extract "AutoIt3.exe".
This is an older verson: 3.3.8.1

https://www.autoitscript.com/autoit3/files/archive/autoit/autoit-v3.3.8.1.zip

Then run your script with it.
Tell me if you still have the same problem.
If you do, then it's definitely something wrong with how you are coding it somehow.

If not, then it's possible some other crazy thing is going on.
Is your version of AutoIt current?


"The mediocre teacher tells. The Good teacher explains. The superior teacher demonstrates. The great teacher inspires." -William Arthur Ward

Share this post


Link to post
Share on other sites
ferbfletcher
15 minutes ago, ripdad said:

Well, you got my curiosity motor running.

I ran the client script that I posted to the 7000 count.
So at this point, i don't know where the problem is.

Download this zipfile and extract "AutoIt3.exe".
This is an older verson: 3.3.8.1

https://www.autoitscript.com/autoit3/files/archive/autoit/autoit-v3.3.8.1.zip

Then run your script with it.
Tell me if you still have the same problem.
If you do, then it's definitely something wrong with how you are coding it somehow.

If not, then it's possible some other crazy thing is going on.
Is your version of AutoIt current?
 

Your script hangs as well, at almost the exact place as my script, if you change the TCPRecv buffer in your server from 8192 to 100.  Whether or not those are good numbers to use is not the point.  The point #1 is that the server should never be able to cause the client to hang like that without any errors, and point #2: you cannot always modify or even see the server configuration, like in my case the server is a linux server that I have no control over.  Also, your script, even at 8192, might still hang (but to prove it you might have to wait a super long time because of that larger buffer).

So, it does seem like the server is causing an issue where it can't accept data past a certain point, but the client (TCPSend) should simply return an error so it can catch that issue instead of hanging forever... no different that if the server goes offline during the sending, the client simply throws an error.  This issue should be no different.  There has to be something within the built-in TCPSend function that isn't properly catching a race condition or something.

 

Edited by ferbfletcher

Share this post


Link to post
Share on other sites
ripdad

I tend to agree.

There have been some TCP changes with newer AutoIt versions.

Which is why I need you to check with that older version of Autoit,
to see if it did the same thing.


"The mediocre teacher tells. The Good teacher explains. The superior teacher demonstrates. The great teacher inspires." -William Arthur Ward

Share this post


Link to post
Share on other sites
ferbfletcher
4 minutes ago, ripdad said:

I tend to agree.

There have been some TCP changes with newer AutoIt versions.

Which is why I need you to check with that older version of Autoit,
to see if it did the same thing.
 

I am currently using version 3.3.14.2

This does NOT happen in 3.3.8.1

Here is what happens in 3.3.8.1:  After it reaches that hanging point, it hangs for a few seconds, and then it continues for awhile, and then it hangs for a few seconds, and then it continues for awhile. 

So, it seems that 3.3.8.1 is retrying after the server stops accepting data, and then it successfully continues sending when the server is ready again, while 3.3.14.2 simply hangs forever.

 

 

Share this post


Link to post
Share on other sites
ripdad

Interesting.

I have no idea what has been changed between the versions to cause that.

Since you don't have any control over the settings of the linux server,
I don't know what to tell you, except make a trac ticket.

https://www.autoitscript.com/trac/autoit

It would be better if you could adjust the TCP server as a work-around, i suppose.
Are you stuck with that particular TCP server, or can you try some other program?

Otherwise, I don't see any harm in using 3.3.8.1 for your client.

Edited by ripdad

"The mediocre teacher tells. The Good teacher explains. The superior teacher demonstrates. The great teacher inspires." -William Arthur Ward

Share this post


Link to post
Share on other sites
ferbfletcher
1 minute ago, ripdad said:

Interesting.

I have no idea what has been changed between the versions to cause that.

Since you don't have any control over the settings of the linux server,
I don't know what to tell you, except make a trac ticket.

https://www.autoitscript.com/trac/autoit

It would be better if you could adjust the TCP server as a work-around, i suppose.
Are you stuck with that particular TCP server, or can you try some other program?

Thank you for your time here.  For this particular project, I am stuck with that server.  As a work-around, I am opening and closing the socket every time inside the loop instead of making a persistent connection, which works, but isn't ideal.  I would like to be able to use persistent connections in the future without being concerned about this issue popping up, because while a program can deal with errors, it is impossible for a program to recover itself when hung.  I have opened a trac ticket ... I'll see what happens with that.

Share this post


Link to post
Share on other sites
ripdad

Okay.

I added another line to my post above in case you missed it.

Have additional questions, let us know.

Take care and hope you get it worked out!


"The mediocre teacher tells. The Good teacher explains. The superior teacher demonstrates. The great teacher inspires." -William Arthur Ward

Share this post


Link to post
Share on other sites
ripdad

I have been giving this some more thought.

RTFC in post #8 is absolutely right.

Even if you wind up using v3.3.8.1 as your client, it will eventually run into a buffer overflow.

The problem is with the TCP server.
For whatever reason, it's not accepting data in a timely manner.

Since there's no way around this, some kind of work-around is needed, like a timeout,
so the server can catch up. Something like a 5 second timeout at every 200 sends.
You might have to play around with it a bit.
 

TCPStartup()

Local $iSocket = TCPConnect("127.0.0.1", 500)

Local $iError, $mydata = ''
Local $x = 0

For $a = 1 To 100
    $mydata &= "xxxxxxxxxxxxxxxxxxxx"
Next

For $i = 1 To 300
    TCPSend($iSocket, $mydata)
    $iError = @error
    If $iError Then
        MsgBox(0, "Error", $iError, 5)
        ExitLoop
    ElseIf $i > 200 Then
        $i = 1
        For $j = 1 To 320; <-- pause for 5 seconds
            Sleep(10)
        Next
    EndIf
    $x += 1
    ToolTip($x)
    Sleep(10)
Next

ToolTip('')
TCPCloseSocket($iSocket)
TCPShutDown()



--Edit--

It would be a good idea to check if you have actual data to send rather than sending blanks in the loop. This will reduce the traffic sent to the server, which will definitely help.

I could not duplicate your issue with either versions of AutoIt. I tried all kinds of ways.

I don't know whats going on with that server, but you should not have to put up with this situation. Perhaps if you had a talk with tech support concerning that linux server, you could work something out with them.

It's also possible that some weird thing is going on with your box or connection as well.

For instance, an anti-virus has detected what it thinks is malicious behavior.

 

Edited by ripdad
inserted script

"The mediocre teacher tells. The Good teacher explains. The superior teacher demonstrates. The great teacher inspires." -William Arthur Ward

Share this post


Link to post
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

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.