Introduction
A few months ago, I wrote a web communication application for a company competition based on an HTML5 feature: websocket. No wonder, websocket will become a very popular and useful way for web based communication and it turns out that windows based client applications can be replaced more and more by web based client applications because of the websocket's arrival. However, there is the reality that not all web browsers support websocket so far. In order to be compatible to the old way, our pure web based application with websocket support cannot be released to the market because most people are using IE (it looks like IE9 supports websocket). Especially in China, IE6 users are everywhere. It makes me feel very bad that people with websocket support web browser are not able to use the advanced feature. Therefore, of late, I'm doing one job to combine comet and websocket together to implement web based communication.
Comet is one old but mature way to do web based communication with AysHttpRequest
. I'm not going to introduce how to implement comet in this article. You can find lots of articles in CodeProject or you can simply have a look at my source code.
Please check:
What I'm doing is to open a comet communication service as well as websocket service on server with the same interface to client connection. Client will automatically select the proper service in terms of the client web browser. Then you can take care of your business data and send the data between web browser and server without considering what web browser you are using.
Using the Code
Server Side
Basically, the server side classes structure is like below:
WebsocketServer
and CometServer
manage their own connections respectively. WillWebCommunicator
takes the responsibility to distribute messages between different services. For example, if there has one message sent from one user.
IWillCommunication
will bring up messageArrived
event no matter whether the message is from Websocket or comet. WillWebCommunicator
will capture this event.
public static void CreateWebSocketService(int port, string origin,
string location, int maxlinks = 100)
{
IWillCommunication communicator = new WebSocketServer(port, origin, location);
communicator.Start(maxlinks);
communicator.ClientMessageArrived +=
new ClientMessageHandle(communicator_ClientMessageArrived);
communicator.Connected += new ConnectionEventHandle(communicator_Connected);
communicator.Disconnected +=
new ConnectionEventHandle(communicator_Disconnected);
_Connections.Add(communicator);
}
public static void CreateCometService(int maxlinks = 100)
{
if (_Connections.Contains(CometServer.Instance)) return;
_Connections.Add(CometServer.Instance);
CometServer.Instance.ClientMessageArrived +=
new ClientMessageHandle(communicator_ClientMessageArrived);
CometServer.Instance.Connected +=
new ConnectionEventHandle(communicator_Connected);
CometServer.Instance.Disconnected +=
new ConnectionEventHandle(communicator_Disconnected);
}
and determine the message is going to be sent to one particular user or all users from WillObject.To
:
if (obj.To == "*")
{
WillWebCommunicator.SendToAll(message.FromJson());
}
else
{
WillWebCommunicator.SendToOne(obj.To, obj);
}
In WillWebCommunicator.SendToAll
, message will be sent to all users both in Websocket server and comet server to make sure everyone get the message.
public static void SendToAll(string message)
{
foreach (IWillCommunication communicator in _Connections)
communicator.SendToAll(message);
}
In WillWebCommunicator.SendToOne
, we will search both websocket server and comet server to locate the right user. There is a Token
property to indicate one particular user with GUID
, this token will be created when user connects to the server for the first time.
public static void SendToOne(string token, string message)
{
foreach (IWillCommunication communicator in _Connections)
communicator.SendToOne(token, message);
}
Client Side
In order to make end users use remote service without considering the client webbrowser, I wrote a "communicator" singleton object to encrypt the connection to service. There 3 basic events in this object: ServerConnectedEvent
, ServerDisconnectedEvent
, MessageArrivedEvent
. Through these 3 events, the final user is able to communicate with server side. If we look at communicator object from object oriented perspective (we didn't really create a class here, the object is created from asynomus function), we can simply assume there are actually 3 classes in the model: baseService
, willCometConnection
, websocketConnection
.
I override open, close, send methods with respective behavior in comet and websocket. The "communicator
" object will determine which real object will be applied with the below code:
if ("WebSocket" in window) return willSocket();
else return willComet();
Another configuration object keeps the comet connection string as well as websocket connection string.
var configuration = function () {
return {
websoketConnstring: "",
cometConnstring: ""
}
} ();
The final user will call the objects like below:
configuration.cometConnstring = "CometConnection.ashx";
configuration.websoketConnstring = "ws://127.0.0.1:8181/WillSocket"
communicator.addMessageArrivedEvent(messageArrived);
communicator.open();
The simple thing you need to do next is to fill your messageArrived
method, run your application and see the magic.
How to Use the Demo
Run up your willwebcommunication
website in your VS2010 or (IIS needs some configuration, U suggest you run it in VS2010). If your computer is in the network, don't forget to change websocketConnstring
to your IP address.
configuration.websoketConnstring =
"ws://127.0.0.1:8181/WillSocket"
Visit Default.html both in IE and Chrome to make sure you opened one comet connection and a websocket connection. In both webpages, you can find the other one's token beginning with "Comet" or "Websocket", click the right one to send a message by clicking the button. (Sorry for the very simple demo. I will improve it soon.)