Flash Socket Class Does Not Wait For Flush
Update
Flash Player Team has confirmed the documentation is wrong. Data is sent as soon as you write to the Socket. In other words, flush() has no purpose.
Flash's Socket class documentation says the following:
flush() method
Flushes any accumulated data in the socket's output buffer. Data written by the write methods is not immediately transmitted; it is queued until the flush() method is called.
However, this is simply not true. A basic test proves the true behavior of the Socket class.
The moment you write to a connected socket, it sends the data and the server receives it. You do not need to call flush(), and, in fact, calling flush() has no effect as far as the server or Flash is concerned. The documentation is not just misleading, it's exactly the opposite of the real behavior.
The socket automatically sends as little as 1 byte. socket.writeByte(0) is immediately sent across the socket.
In direct opposition to the documentation for Socket, data is not queued, it is immediately transmitted across the socket. Calling flush() does nothing. The data is already sent. There is absolutely no difference from the server's perspective whether I call flush() or not, and I can write millions of bytes on a Socket and never call flush() and there is no negative effect as far as all testing I have conducted has been able to show.
Flash sends data across the Socket in 536 byte packets. Anything larger than 536 bytes gets split into separate packets. So, if you send 537 bytes, Flash sends two packets, one that's 536 bytes and one that's 1 byte.
The internal limit that Flash can send via Socket appears to be 524,744 bytes. If you set up your server to not read off the socket, 524,744 bytes is the point that Flash's socket becomes blocked. However, Flash does not let you know that the Socket is blocked or that there are any bytes sitting on the Socket unsent.
This behavior is exacerbated by the fact that there is no way to track progress on Socket sending, only receiving. There is no event that fires if you're blocked, and you have no way of knowing that the server did not receive your entire transmission unless you have some kind of expected response that you did not receive within a certain time limit, which is not something you can reliably measure considering latency and/or varying bandwidths, and the fact that you have no idea how much data the server has received.
If you send 1,000,000 bytes and set up your server to wait until you send 524,744 bytes to read it, Flash does not even need you to call flush() to send the remaining 475,256 bytes, it happens automatically. No flush() required, and you don't even know that the Socket was blocked.
It's worth pointing out that if the server has a receive buffer (we set it to 8040 bytes), Flash does not honor it when running in the IDE, running as a SWF in the debug player on the desktop, or in AIR. It only honors it when it's running in a browser (tested in Chrome, Firefox and IE on Windows). Regardless, Flash does not report that only 8040 bytes were sent, and, again, flush() was not called but the bytes were sent anyway.
The behavior is identical whether you use socket.writeByte() and write 1 byte to the socket at a time, or use writeBytes() and write all the bytes to the socket at once.
FileReference lets you track progress on a HTTP Socket POST of bytes. I don't know why they still have not given us progress on the Socket sending, and I also don't know why the Socket doesn't wait for you to tell it to upload, like the documentation says it does.
As far as any Actionscript code you can write is concerned, every single byte you write to a socket is sent instantaneously. I can watch my network and see bytes as they're being sent, but according to my code's behavior, I can transmit gigs of data across a socket instantly. I tell the Socket to send it, and the Socket basically behaves as if it's a synchronous event and every byte has been sent. Obviously, there is a good reason for this behavior (not locking up Flash for Socket transmissions), but there's no good reason to not inform me of the progress.
It's bad to assume that all the data on the Socket was sent instantly. It's also complicated by the fact that Flash doesn't wait for me to call flush() before sending data.
I would appreciate anyone from Adobe or anyone else who has more information on Flash's Socket behavior, and I'm also curious why the documentation for Socket has been incorrect for years now and nobody has pointed it out.
More importantly, how long until we can see progress of bytes sent on a Socket?
Posted in AS3, Actionscript, Flash, Rants
December 8th, 2009 at 2:10 pm
Unfortunately sockets are kinda like this at the system level as well. Flushing just ensures that there is no queued data but once you chuck the data into send() it gets sent whenever the tcp stack gets around to it. Check out http://msdn.microsoft.com/en-us/library/ms740149%28VS.85%29.aspx Specifically: "If no error occurs, send returns the total number of bytes sent, which can be less than the number requested to be sent in the len parameter." At least the winsock api tell you how many bytes you've sent…
December 8th, 2009 at 2:15 pm
Ok, so it's confirmed (from you and elsewhere) that Socket sends the data the moment you write anything to it.
The documentation is wrong throughout (every write function says it doesn't send until you call flush, and flush says it sends the data, but, in fact, does nothing because the data is already sent instantly).
December 8th, 2009 at 5:05 pm
Nice catch, Steven, thank you. I'm updating the documentation source now and we'll push the changes live as soon as we can.
Jody Bleyle
Sr. Technical Writer
Adobe Systems, Inc.
December 8th, 2009 at 5:15 pm
Thanks! Now how about returning progress, or being able to see how many bytes remain on the socket so I can tell if the socket is blocked, etc.
December 9th, 2009 at 6:10 am
As Steven said there are huge problems with getting sending progress with Socket class. So don;t forget to vote on this bug@Adobe JIRA:
http://bugs.adobe.com/jira/browse/FP-6
February 23rd, 2010 at 8:25 pm
It's been almost 3 months and the documentation remains unchanged. Will you be updating this anytime soon?
March 11th, 2010 at 8:49 am
So, how to flush socket?
March 11th, 2010 at 2:18 pm
There is no flushing of a socket. The moment you say socket.writeWhatever, the bytes are sent to the server immediately.
April 8th, 2010 at 2:02 pm
As to the flush() behavior, on Mac and Linux, flush() is called implicitly between execution frames. So if you wrote two bytes in different write calls in the same function, for example, those two bytes are sent together. If the writes were separated by an async event, then they would be sent separately.
However, on Windows, data is never sent unless you call flush(). The platform inconsistency is a bug, but the docs were essentially correct (just incomplete).
April 8th, 2010 at 2:07 pm
That is incorrect. You haven't tested this. If you had, you would know that what you just said is wrong.
I am on Windows and when I write to the Socket, the server immediately receives it. Same thing happens on Mac and Linux. There is no platform inconsistency.
I'm surprised that Adobe still hasn't updated the documentation.