Document Version 1.0
Copyright © 2012-2013 beijing.beijing.012@gmail.com
Beside Server-Sent Events, WebSocket is an another important feature introduced by HTML5 for browser to update web page content automatically from server. The most important differences between WebSocket and Server-Sent Events are:
- Server-Sent Events is one way communication whereas WebSocket use full-duplex channel.
- Server-Sent Event is HTTP, WebSocket introduced new protocol "ws" protocol
Here I am not going compare WebSocket and Server-Sent Events in detail, I will just show you a simple WebSecket sample to get a feeling.
A sample of Server-Sent Events could be found here http://milestonenext.blogspot.de/2013/07/html5-server-sent-events-sample-with.html
In the example below, browser opens a window, send text message to server. Server just send message back to browser, shown in the window. (by the way, the sample could be extended with small effort to work as a chat application ...)
The client is just a html page with embedded javascript. The Server is a Java Servlet web application running on Tomcat 7.0.29. (WebSocket, "ws" protocol support with Tomcat since version 7.0.24 ).
The client is just a html page with embedded javascript. The Server is a Java Servlet web application running on Tomcat 7.0.29. (WebSocket, "ws" protocol support with Tomcat since version 7.0.24 ).
1. Create a simple web application "WebSocketSample"
User your favorite IDE (I use Eclipse) to create a Web Application. Be sure to use servlet 3.x style.
The sample web application consists of :
- two java classes, which are the server side code
- one "html" page which is the client
2. MyWebSocketServlet.java
The sample uses Tomcat implementation of of "WebSocket", so we need to have "catalina.jar" on class path.
Add servlet-api.jar to class path as well.
package sample;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.catalina.websocket.StreamInbound;
import org.apache.catalina.websocket.WebSocketServlet;
/**
* WebSocketServlet is contained in catalina.jar. It also needs servlet-api.jar
* on build path
*
* @author wangs
*
*/
@WebServlet("/wsocket")
public class MyWebSocketServlet extends WebSocketServlet {
private static final long serialVersionUID = 1L;
// for new clients, <sessionId, streamInBound>
private static ConcurrentHashMap<String, StreamInbound> clients = new ConcurrentHashMap<String, StreamInbound>();
@Override
protected StreamInbound createWebSocketInbound(String protocol,
HttpServletRequest httpServletRequest) {
// Check if exists
HttpSession session = httpServletRequest.getSession();
// find client
StreamInbound client = clients.get(session.getId());
if (null != client) {
return client;
} else {
client = new MyInBound(httpServletRequest);
clients.put(session.getId(), client);
}
return client;
}
public StreamInbound getClient(String sessionId) {
return clients.get(sessionId);
}
public void addClient(String sessionId, StreamInbound streamInBound) {
clients.put(sessionId, streamInBound);
}
}
3. MyInbund.java
Since Tomcat's WsOutbound has indirect dependency on "tomcat-koyote.jar", please add this jar to class path to resolve compile error like "the hierarchy of the type ... is inconsistent ..."
package sample;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import javax.servlet.http.HttpServletRequest;
import org.apache.catalina.websocket.MessageInbound;
import org.apache.catalina.websocket.WsOutbound;
/**
* Need tomcat-koyote.jar on class path, otherwise has compile error "the hierarchy of the type ... is inconsistent"
* @author wangs
*
*/
public class MyInBound extends MessageInbound{
private String name;
private WsOutbound myoutbound;
public MyInBound(HttpServletRequest httpSerbletRequest) {
}
@Override
public void onOpen(WsOutbound outbound) {
System.out.println("on open..");
this.myoutbound = outbound;
try {
this.myoutbound.writeTextMessage(CharBuffer.wrap("hi, what's your name?"));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void onClose(int status) {
System.out.println("Close client");
//remove from list
}
@Override
protected void onBinaryMessage(ByteBuffer arg0) throws IOException {
}
@Override
protected void onTextMessage(CharBuffer inChar) throws IOException {
System.out.println("Accept msg");
CharBuffer outbuf = CharBuffer.wrap("- " + this.name + " says : ");
CharBuffer buf = CharBuffer.wrap(inChar);
if(name != null) {
this.myoutbound.writeTextMessage(outbuf);
this.myoutbound.writeTextMessage(buf);
} else {
this.name = inChar.toString();
CharBuffer welcome = CharBuffer.wrap("== Welcome " + this.name + "!");
this.myoutbound.writeTextMessage(welcome);
}
this.myoutbound.flush();
}
}
4. wssockrt.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Tomcat web socket</title>
<script type="text/javascript">
var ws = new WebSocket("ws://localhost:8080/WebSocketSample/wsocket");
ws.onopen = function () {
};
ws.onmessage = function(message) {
document.getElementById("msgArea").textContent += message.data + "\n";
};
function postToServer() {
ws.send(document.getElementById("msg").value);
document.getElementById("msg").value = "";
}
function closeConnect() {
ws.close();
}
</script>
</head>
<body>
<div>
<textarea rows="4" cols="100" id="msgArea" readonly></textarea>
</div>
<div>
<input id="msg" type="text"/>
<button type="submit" id="sendButton" onclick="postToServer()">Send</button>
</div>
</body>
</html>
5. Export ".war" and deploy it on a running Tomcat
Export the "WebSocketSample.war"and deploy it on a running Tomcat server.
Open the link below with browser:
http://localhost:8080/WebSocketSample/wsocket.html
You will see:
Now type your name and send:
So it woks!
6. The "WebSocket" Header
When we take a close look at the headers of the Request and Response above: