Zhong Yu, 2014-07-24
Most server-side WebSocket APIs are event-based, that is, the application provides callbacks in response to events like
onError. The application code is passive, invoked only by the framework when events occur.
This is different from the traditional socket API, which provides methods like
read() to be invoked by the application. The application code controls logic flow, it calls
read() whenever it chooses to.
The difference is a little odd, since WebSocket is not much different from TCP socket, both are full-duplex transport protocols. We would have thought that applications will interact with both protocols in similar ways.
The event-based API has an apparent problem that the application is subject to the whim of the remote peer, because it has to handle inbound messages even when none is expected. For example, suppose the application protocol is half-duplex request-response style; when the application is still processing request#1, which takes some time, request#2 comes in and is shoved to the application. The problem can be solved or avoided in various ways, but none is as natural as letting the application poll the inbound when it chooses to.
That being said, the event-based design is obviously a success in practice, people are using it happily to build their WebSocket applications. This is probably because in most use cases to date, the client and server applications are written by the same team, there are implicit cooperation and coordination between the two ends. It is possible that the event-based API is perfectly fine for typical WebSocket applications we've been seeing so far.
For that reason, we design our WebSocket API to mirror traditional socket API, so that applications can have more control in case they need to. See WebSocketChannel. Of course, if an application really wants an event-based API instead, it's very easy to build a DIY one on top of our API.