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. 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? Thanks! Regards, Konstantin Preißer --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org