On Sat, Oct 5, 2013 at 4:56 PM, Konstantin Preißer <kpreis...@apache.org>wrote:
> Hi Niki, > thank you for your reply. > > > -----Original Message----- > > From: Niki Dokovski [mailto:nick...@gmail.com] > > Sent: Saturday, October 5, 2013 7:47 AM > > To: Tomcat Developers List > > Subject: Re: 8.0.x / 7.0.x progress > > > > I have installed Wireshark now and can confirm that Firefox (after it > is > > > resumed) still sends data over the TCP connection which Tomcat seems > not > > to > > > be able to read. > > > > > > > Are there ACKs for the TCP packets? > > I'll try to reproduce the case. > > Yes, I verified with Wireshark that Tomcat ACKs these packets correctly, > but does not seem to be able to process them. I continued to send data from > Firefox (SEQ went up to 61373) to ensure that the ACKs were not just > resulting from buffering somewhere in the Windows or Java network stack, > and I can confirm that Tomcat still ACKed these SEQ numbers. > > Note, that when using the BIO connector, everything works fine - the > problems only appear with NIO or APR connector. > > > > > > > B) For BIO connector: > > > > > I noticed that on Tomcat with BIO connector, when using a > > > > RemoteEndpoint.Async to asynchronously send data over the > > WebSocket > > > > connection, sendText(String, SendHandler) (or similar methods) will > > > block if > > > > the Remote endpoint does not read data from the connection, whereas > > for > > > > NIO and APR connector this method will always return immediately. > > > > > Is it intended that for the BIO connector those methods are > blocking? > > > As > > > > the javadoc says, "Initiates the asynchronous transmission of a text > > > message. > > > > This method returns before the message is transmitted.", I would have > > > > expected that e.g. another Thread is used to write in blocking mode, > so > > > that > > > > the sendText() method can return immediately. > > > > > > > > You can't do non-blocking IO with the BIO connector. All > communication > > > > with BIO is blocking. This is working as designed. > > > > > > OK, but my understanding was that there is a difference between the > > terms > > > "synchronous/asynchronous" and "blocking/non-blocking" (but maybe the > > > meaning differs from programming language to programming language). > > > > > > > An excellent and detailed explanation on this topic can be found in > "UNIX > > Network Programing" R. Stevens Vol 1 3td ed. p154-p160 > > Thank you for that information. > However, currently I don't have that book (and I'm not very familiar with > UNIX as I'm a windows guy ;) ), but please let me try to illustrate my use > case with the Snake example. > > > The SnakeTimer class has a broadcast() method that broadcasts a message to > all connected clients by looping over them and calling > snake.sendMessage(...), which in turn will call > session.getBasicRemote().sendText(msg) to send the message. As the methods > of RemoteEndpoint.Basic are blocking, this means that if some client > establishes a Websocket connection and stops to read from it, then after > some time the broadcast() method will hang waiting for sendText() to > complete, which will block until that specific client continues to read > data. This means that messages cannot be broadcasted to all other clients, > so for them all snakes stop moving. > > A simple way that comes in my mind to solve this would be to use an > additional thread for each connected client. This thread would take message > from a Queue and send them to the client while the SnakeTimer's broadcast() > would add a messages to the queue of each client. Then, if some client's > sendText() method blocks (because the client does not read data from the > connection), it does not interfere with the other clients, so they still > would see the snakes moving. > > However, this is costly because it would require an additional thread per > Websocket connection. > > So, another way would be to look at RemoteEndpoint.Async that can send > messages asynchronously. The javadoc (from Oracle) of > Async#sendText(String, SendHandler) says, "Initiates the asynchronous > transmission of a text message. This method returns before the message is > transmitted." > For me, this looks like I can call this method and be sure that it does > not block when some client does not read data from the websocket > connection. Therefore, I could change the broadcast() method to use > RemoteEndpoint.Async#sendText(String, SendHandler) to start async sending > of a message, if no message is already on the way to the client (if it is, > it would need to buffer them somewhere). Then, when SendHandler#onResult() > callback is called, the code can look if it needs to send additional > messages to the client (and if yes, call sendText(...) again). > This will remove the need from using a separate thread for sending the > data. > > The problem is now that if Tomcat's implementation of this > Async#sendText(...) method is blocking when using the BIO connector, it > will mean that with BIO I get the problem again that the snakes will stop > moving on all clients if one client stops reading data (might be considered > as a DoS), but if I use NIO or APR, everything will be fine. That would > mean that I have to use different implementations of broadcasting data to > clients, depending on the underlying connector that is being used (blocking > or non-blocking). > > Therefore, I would expect that RemoteEndpoint.Async#sendText(String, > SendHandler) behaves the same regardless of whether BIO or NIO is used. I see. To me, this is an implementation detail, because from specification point of view the WebSocket container with the appropriate configuration supports the asynchronous case. Hence there is no violation of the spec. Now, it is completely different thing if all configurations support the asynchronous behavior. Anyway, this is still an interesting case and it is valuable to know the corner cases. I'll take a look into the details. > For NIO, Tomcat actually can use a non-blocking write operation and only > acquire a thread for calling the SendHandler#onResult() callback (but I > don't have much knowledge of the internal Tomcat code so I could be wrong > here); whereas for BIO, Tomcat could acquire a thread for the complete > duration of the blocking write operation plus calling the callback (so it > would still be an async write operation although the underlying I/O uses > blocking write). > > > Have I missed something here? > I don''t think so. > > Thanks! > > > Regards, > Konstantin Preißer > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org > For additional commands, e-mail: dev-h...@tomcat.apache.org > >