Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [jetty-users] WebSocketListener clarification

Answers inline ..

On Wed, Aug 21, 2013 at 4:28 AM, Kasper Nielsen <kasperni@xxxxxxxxx> wrote:

A couple of questions about the WebSocketListener interface, which is not completely clear by reading the Javadoc.

1) Concurrent invokes
Methods are always invoked one at a time?
So, for example, onWebSocketError() is never concurrently invoked with  onWebSocketText().

In general, yes, this is true.
However, there are scenarios where this might be perceived as false.

Jetty calls onWebSocketText(String), and as you are processing it, you allow an unhandled exception to flow out of your code.
This is caught by Jetty, and a websocket close is issued to the remote side.
Which also results in onWebSocketError(Throwable) being called for the unhandled exception.
And a onWebSocketClose(int, String) being called for the abnormal close.


onWebSocketClose and onWebSocketError are never both invoked at the end of the lifecycle of a listener. If onWebSocketError is invoked, onWebSocketClose is never invoked, right?

This is possibly.
You should always receive a onWebSocketClose.
And if the cause of the close was due to abnormal behavior on your WebSocket side (such as an uncaught exception, or protocol error) then you will receive a onWebSocketError as well.

It is also possible for you to initiate a Session.close(), triggering the close handshake, get a OnWebSocketError(Throwable) indicating that the connection isn't alive (think SocketError, IOException, EOFException, etc...) and then a local abnormal close on onWebSocketClose(int, String)


The first method invoked is always onWebSocketConnect?
For example, onWebSocketError is never invoked as the first operation?

In general, Yes, onWebSocketConnect() is the first method called.

Even if you have a connection issue, the behavior would be as follows.
Server Socket: If the handshake or connect doesn't work, the more fundamental upgrade mechanism will respond via the HTTP response mechanism the error situation.
Never notifying the socket implementation of the connect attempt or error.
Client Socket: If you have a problem connecting, or during the handshake, you'll get that exception back via the Future on the WebSocketClient.connect() call.

However, it is possible with annotated WebSockets to have this appear to be false.
Example:  Your annotated websockets has itself declared like this ...
public class MySocket {
    public void onConnect(Session session) {

    public void onError(Throwable t) {
Obviously, the unannotated onConnect isn't going to be called.


So the lifecycle of a WebSocketListener is roughly as follows:

onWebSocketConnect() -> followed by
0 or more onWebSocketBinary() or onWebSocketText() (sequentiel) -> followed by
onWebSocketError or onWebSocketClose -> no listener methods is invoked after this.

It is possible to receive more than 1 onWebSocketError().
Even after the onWebSocketClose().

  You are using the streaming API from a thread of your own to write a big message to the Remote endpoint, lets say via the Jetty 9.1 RemoteEndpoint.getWriter() mechanism.
  The remote responds to your message with a sudden close code 1009 (Message too large)
  Internally, the implementation is queuing and fragmenting the various parts of your message to be sent when it can.
  You'll get a onWebSocketClose() with the details from the remote endpoint's 1009 close, then shortly afterwords your thread will get an exception on the next write attempt.
  Your socket will be notified of the failure to write in onWebSocketError() too.
  All pending frames in the queue that are unwritten will have their callbacks / futures failed as well (this is an async operation).
  If your thread decides to cleanup in a catch block and issue a Session.close(), you might get an IOException during that call (dependent on threading behavior) , but you'll get another onWebSocketError() indicating the failure to issue a close. (as the socket is already closed).

Example 2:
  You are using extensions, such as the deflate extension.
  Something in the extension is unhappy and throws an exception.
  This will trigger the websocket implementation to close the connection.
  This could result in onWebSocketError() from the extension, and for actions that extension was trying to handle.
  You could see in your socket a onWebSocketError() from the extension, a onWebSocketClose() from the implementation, and another onWebSocketError() from your own pending actions that failed during processing deep in the bowels of the implementation.



- Joakim 

Back to the top