New Java Servlet based Socket.IO server

656 views
Skip to first unread message

Tad Glines

unread,
Oct 24, 2010, 1:13:14 AM10/24/10
to sock...@googlegroups.com
I've created a Java Servlet based Socket.IO server. All the transports are implemented and I've tested all but htmlfile in Firefox and Chrome 6. I'm not sure which browser uses htmlfile but if someone can tell me, I'll try and test that one as well.

Testing at this point consisted of using the chat example and making sure messages went both ways.

This server will not work with existing versions of Socket.IO because I changed the message encoding format in order to support a few extra message types.


The socketio-java project is hosted at: http://code.google.com/p/socketio-java/
My fork of the Socket.IO project is at: http://github.com/tadglines/Socket.IO

-Tad

Guillermo Rauch

unread,
Oct 24, 2010, 1:44:22 AM10/24/10
to sock...@googlegroups.com
Tad,

First, amazing work on the Java server library. I'm sure many people will find this interesting.

Secondly, lots of interesting stuff in your client fork. Thanks for making it public
Would you mind separating the following into patches / pull requests?
  • Added simple windows bat script to compile the js.
  • Added onerror handler to xhr-polling that'll call _onDisconnect(); This way if the server replys with an error, the client will disconnect instead of trying to get again.
  • Add explicit close message from client and server in order to support orderly shutdown of connection.
I'm curious about the reasons behind:
  • Added onopen handler in WebSocket that send a simple message.
  • Removed JSON parsing, it's up to the client to treat the message as JSON. 
The extra bytes are little overhead for the most common usage case (which is, of course, people sending JSON)


--
Guillermo Rauch
http://devthought.com

Tad Glines

unread,
Oct 24, 2010, 11:16:47 AM10/24/10
to sock...@googlegroups.com
Secondly, lots of interesting stuff in your client fork. Thanks for making it public
Would you mind separating the following into patches / pull requests?
  • Added simple windows bat script to compile the js.
  • Added onerror handler to xhr-polling that'll call _onDisconnect(); This way if the server replys with an error, the client will disconnect instead of trying to get again.
  • Add explicit close message from client and server in order to support orderly shutdown of connection.
The first two are self contained so, I can probably do that. Can you describe the process using git/github, I've never used it before. I'm used to Subversion and Mercurial.

As for the third one, that requires the new message encoding. The new message encoding format is "~<opcode>~<size>~<message>". The opcodes are:
1 - Session ID (only from server to client, must be first message received by client.)
2 - Heartbeat interval (Only from server to client.)
3 - Close message (Indicates that the sender has no more messages to send and that the receiver should abort the connection and discard any buffered messages.)
4 - Ping message (Sent by server)
5 - Pong message (required reply to ping message.)
6 - Text message

I've borrowed from the draft-ietf-hybi-thewebsocketprotocol-03. The opcodes don't match at the moment. I thought of exposing the opcode via:
void sendMessage(byte opcode, String message)
void onMessage(byte opcode, String message)
instead of the current
void sendMessage(String message)
void onMessage(String message)
but that would require either allowing the client to send control frames, or throwing an exception if a non-data opcode is used.
An alternative would be to have:
sendTextMessage(String message)
sendJSOBNMessage(String json)
onTextMessage(String message)
onJSONMessage(String json)

I'm still on the fence about which way to go with it, so I kept it simple and restricted it to just text and leave the interpretation up to the client.
 
I'm curious about the reasons behind:
  • Added onopen handler in WebSocket that send a simple message.
There is a bug in the jetty 7.1.6 implementation WebSocket. At the time that WebSocket.onConnect(Outbound outbound) is called, the websocket 16 byte reply hasn't been sent, and if the client called outbound.sendMessage() that message would get sent before the 16 byte handshake and the connection gets dropped by the browser. So, I have the client send a simple message, and don;t call SocketIOInbound.onConnect(SocketIOOutbound outbound) until that message is recieved. That was the client can call outbound.sendMessage() without the connection being dropped.

This bug appears to have been fixed in the 7.2.0 release, but this bit of rigmarole is still needed for backward compatibility. At the moment, my code will not work with jetty 7.2.0 web sockets.

  • Removed JSON parsing, it's up to the client to treat the message as JSON. 
The extra bytes are little overhead for the most common usage case (which is, of course, people sending JSON)

See above.

-Tad

Tad Glines

unread,
Oct 26, 2010, 4:09:41 PM10/26/10
to sock...@googlegroups.com
I've begun documenting the Socket.IO protocol and I'm working on a proposed change to the Socket.IO API and semantics.

The protocol page is: http://code.google.com/p/socketio-java/wiki/Protocol
The proposed API changes are at: http://code.google.com/p/socketio-java/wiki/PropsedSocketIOInterfaceSpecification

The second one only has the client side in it right now, but I'm going to add the Java server side API as well.

I welcome comments and suggestions.

One thing I'm still on the fence about is persistent sessions. The argument is that the end-to-end session shouldn't fail due to transient connection drops. The problem with implementing this is that there is no way to know if the last message sent actually made it to the other end when WebSockets are used. This is because the browser buffers the messages and if the connection drops there's no way to know which messages are still in the buffer. The only way to reliably do this would be to add a sequence number to each message and only discard them from the send buffer when an ACK is received from the other end. This seems like an added complication.

Thoughts?

-Tad

Guillermo Rauch

unread,
Oct 26, 2010, 4:11:56 PM10/26/10
to sock...@googlegroups.com
I really like most of these. Are you contemplating heartbeat timeout as a disconnect reason, or do you think a timeout event is more appropriate?

Tad Glines

unread,
Oct 26, 2010, 4:22:52 PM10/26/10
to sock...@googlegroups.com
I was planing to add a second argument to the DISCONNECT event handler that specifies the disconnect reason.

Possible values are:
EXPLICIT (The disconnect method was called and an orderly close had not progressed to the CLOSE_SIMPLE state).
TIMEOUT (regardless of the kind of timeout.
CLOSE_FAILED (an orderly close was started, but the connection was dropped before the initial Close message made it out the door).
ERROR (Any other reason the disconnect happened).

For the disconnect type of CONNECT_FAILED I'd add the following sub types:
AUTHENTICATION_FAILURE (The connection attempt failed due to an authentication problem).
PERMISSION_DENIED (The connection attempt failed due to an authentication problem).
ERROR (Any other reason the connect failed).

In all cases the third argument should probably be a user friendly error message.

In the case of WebSocket transport the auth/permisiosn types would not be used since the WebSocket standard doesn't include this kind of error.
I'm seriously disappointed in that specification. I realize they where trying to keep it simple, but it's a bit too simple right now.

-Tad

Tad Glines

unread,
Oct 26, 2010, 9:15:16 PM10/26/10
to sock...@googlegroups.com
I've updated the mentioned Wiki pages with more details. I think I've settled on a target APi for the first "version" of socketio-java.

I also added pages that provide the Java interfaces used on the client and server side: http://code.google.com/p/socketio-java/w/list

-Tad

Tad Glines

unread,
Oct 30, 2010, 12:00:20 AM10/30/10
to sock...@googlegroups.com
I've finalized the API changes. In both the Socket.IO fork and the socketio-java repo the changes are on a branch named "api-changes".

I simplified things a little in that I eliminated the 'close' event and just added to disconnect reason for the disconnect event. I also simplified the close semantics from what I had originally considered. Now either end can initiate an orderly close and the other side can acknowledge the close. This means that only the initiator can be certain all its messages arrived at the other end.

In the client interface disconnect() simply drops the connection, discarding any unsent messages. The close() method will initiate an orderly close.

-Tad
Reply all
Reply to author
Forward
0 new messages