How does bisocket transport work
The bisocket client and server invokers inherit most of their functionality from the socket invokers, with the principal exception of overriding a method in the client invoker called createSocket(). If the client invoker is on the client side, then createSocket() simply calls the super implementation. The heart of the bisocket transport is in handling the case of creating a connection from a callback client invoker on the server side to a callback server invoker on the client side, which is mandated to occur without the use of a ServerSocket on the client side. Whenever the bisocket transport is informed by an application of its intention to use push callbacks, the client side creates a secondary "control" connection, and subsequently, whenever the callback client invoker needs to create a connection to the callback server, it sends a request over the control connection asking the client side to establish the connection. The server side of the transport maintains a secondary ServerSocket that accepts connection requests from the client side, and whenever a socket is created it is passed to whichever callback client invoker requested it. The client invoker, which inherits the socket transport's connection pool management facility, adds the new socket to its connection pool. Note that if the control connection were to fail, no new connections could be created for the callback client invoker, and eventually callback transmission could come to a halt. The client and server invokers work together, therefore, to maintain a heartbeat on the control connection and to recreate the control connection automatically should it fail. In particular, the server side sends out ping messages on the control connection, and the client side needs to receive a ping message within some configured window in order to consider the connection to be functional.