The emergence of the WebSocket protocol is undoubtedly one of the most exciting features of HTML5. It can effectively replace the Comet technology and Flash XmlSocket to implement HTTP-based bidirectional communication. Currently, mainstream browsers such as Chrome, Firefox, IE10, Opera10, and Safari all support WebSocket. In addition, some good WebSocket projects, such as Resin, Jetty7, and pywebsocket, also appeared on the server. However, this article will introduce how to use the powerful Netty framework (Netty-3.5.7.Final) to implement WebSocket server.
The performance advantages of the Netty3 framework do not need to be discussed, but what makes developers more comfortable is that Netty3 also provides a wide range of protocol implementations, including HTTP, Protobuf, and WebSocket, developers can easily implement their own Socket Server. According to the general idea of Netty3, we need to prepare the following three files:
1. WebSocketServer. java
2. WebSocketServerHandler. java
3. WebSocketServerPipelineFactory. java
The preceding three files contain the main program logic, service processing logic, and Socket Pipeline setting logic. Java code implementation is as follows:
WebSocketServer. java
[Java]
Public class WebSocketServer
{
Private final int port;
Public WebSocketServer (int port ){
This. port = port;
}
Public void run (){
// Set Socket channel factory
ServerBootstrap bootstrap = new ServerBootstrap (
New NioServerSocketChannelFactory (
Executors. newCachedThreadPool (),
Executors. newCachedThreadPool ()));
// Set the Socket pipeline factory
Bootstrap. setPipelineFactory (new WebSocketServerPipelineFactory ());
// Start the service and start listening
Bootstrap. bind (new InetSocketAddress (port ));
// Print the prompt information
System. out. println ("Web socket server started at port" + port + '.');
System. out. println ("Open your browser and navigate to http: // localhost:" + port + '/');
}
Public static void main (String [] args ){
Int port;
If (args. length> 0 ){
Port = Integer. parseInt (args [0]);
} Else {
Port = 8080;
}
New WebSocketServer (port). run ();
}
}
WebSocketServerPipelineFactory. java
[Java]
Public class WebSocketServerPipelineFactory implements ChannelPipelineFactory {
Public ChannelPipeline getPipeline () throws Exception {
// Pipeline configuration and logic
ChannelPipeline pipeline = pipeline ();
Pipeline. addLast ("decoder", new HttpRequestDecoder ());
Pipeline. addLast ("aggregator", new HttpChunkAggregator (65536 ));
Pipeline. addLast ("encoder", new HttpResponseEncoder ());
Pipeline. addLast ("handler", new WebSocketServerHandler ());
Return pipeline;
}
}
WebSocketServerHandler. java
[Java]
Public class WebSocketServerHandler extends SimpleChannelUpstreamHandler
{
Private static final InternalLogger logger = InternalLoggerFactory
. GetInstance (WebSocketServerHandler. class );
Private static final String WEBSOCKET_PATH = "/websocket ";
Private WebSocketServerHandshaker handshaker;
@ Override
Public void messageReceived (ChannelHandlerContext ctx, MessageEvent e)
Throws Exception {
// Process and accept messages
Object msg = e. getMessage ();
If (msg instanceof HttpRequest ){
HandleHttpRequest (ctx, (HttpRequest) msg );
} Else if (msg instanceof WebSocketFrame ){
HandleWebSocketFrame (ctx, (WebSocketFrame) msg );
}
}
@ Override
Public void exceptionCaught (ChannelHandlerContext ctx, ExceptionEvent e)
Throws Exception {
// Handle exceptions
E. getCause (). printStackTrace ();
E. getChannel (). close ();
}
Private void handleHttpRequest (ChannelHandlerContext ctx, HttpRequest req)
Throws Exception {
// Only accept http get requests
If (req. getMethod ()! = GET ){
SendHttpResponse (ctx, req, new DefaultHttpResponse (HTTP_1_1,
FORBIDDEN ));
Return;
}
// Start Websocket handshake
WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory (
GetWebSocketLocation (req), null, false );
Handshaker = wsFactory. newHandshaker (req );
If (handshaker = null ){
WsFactory. sendUnsupportedWebSocketVersionResponse (ctx. getChannel ());
} Else {
Handshaker. handshake (ctx. getChannel (), req). addListener (
WebSocketServerHandshaker. HANDSHAKE_LISTENER );
}
}
Private void handleWebSocketFrame (ChannelHandlerContext ctx,
WebSocketFrame ){
// Websocket handshake ends
If (frame instanceof CloseWebSocketFrame ){
Handshaker. close (ctx. getChannel (), (CloseWebSocketFrame) frame );
Return;
} Else if (frame instanceof PingWebSocketFrame ){
Ctx. getChannel (). write (new PongWebSocketFrame (frame. getBinaryData ()));
Return;
} Else if (! (Frame instanceof TextWebSocketFrame )){
Throw new UnsupportedOperationException (String. format ("% s frame types not supported ",
Frame. getClass (). getName ()));
}
// Process the received data (converted to uppercase) and return
String request = (TextWebSocketFrame) frame). getText ();
If (logger. isDebugEnabled ()){
Logger. debug (String. format ("Channel % s encoded ed % s", ctx. getChannel (). getId (), request ));
}
Ctx. getChannel (). write (new TextWebSocketFrame (request. toUpperCase ()));
}
Private static void sendHttpResponse (ChannelHandlerContext ctx,
HttpRequest req, HttpResponse res ){
// Return the HTTP Error Page
If (res. getStatus (). getCode ()! = 200 ){
Res. setContent (ChannelBuffers. copiedBuffer (res. getStatus (). toString (), CharsetUtil. UTF_8 ));
SetContentLength (res, res. getContent (). readableBytes ());
}
// Send the returned information and close the connection
ChannelFuture f = ctx. getChannel (). write (res );
If (! IsKeepAlive (req) | res. getStatus (). getCode ()! = 200 ){
F. addListener (ChannelFutureListener. CLOSE );
}
}
Private static String getWebSocketLocation (HttpRequest req ){
Return "ws: //" + req. getHeader (HttpHeaders. Names. HOST) + WEBSOCKET_PATH;
}
}
The logic of the above Code is clear: first, set WebSocketServerPipelineFactory in WebSocketServer; then, set WebSocketServerPipelineFactory in WebSocketServerPipelineFactory; then, process the request and return the result in WebSocketServerHandler, the most important processing logic is in the handleWebSocketFrame method, that is, to convert all the obtained request information into uppercase and return data. Finally, run WebSocketServer. java to start the WebSocket service and listen to the local port 8080. At this point, the WebSocket server is all ready. Here, we have developed a simple HTTP server with the following interface:
Next, we need to prepare a WebSocket client implemented by Javascript. The implementation is very simple. The Javascript code is implemented as follows:
Websocket.html
[Html]
<Html> <Body>
<Script type = "text/javascript">
Var socket;
If (! Window. WebSocket ){
Window. WebSocket = window. WebSocket;
}
// Javascript Websocket Client
If (window. WebSocket ){
Socket = new WebSocket ("ws: // localhost: 8080/websocket ");
Socket. onmessage = function (event ){
Var ta = document. getElementById ('responsetext ');
Ta. value = ta. value + '\ n' + event. data
};
Socket. onopen = function (event ){
Var ta = document. getElementById ('responsetext ');
Ta. value = "Web Socket opened! ";
};
Socket. onclose = function (event ){
Var ta = document. getElementById ('responsetext ');
Ta. value = ta. value + "Web Socket closed ";
};
} Else {
Alert ("Your browser does not support Web Socket .");
}
// Send Websocket data
Function send (message ){
If (! Window. WebSocket) {return ;}
If (socket. readyState = WebSocket. OPEN ){
Socket. send (message );
} Else {
Alert ("The socket is not open .");
}
}
</Script>
<H3> Send: <Form onsubmit = "return false;">
<Input type = "text" name = "message" value = "Hello World! "/> <Input type =" button "value =" Send Web Socket Data "onclick =" send (this. form. message. value) "/>
<H3> Receive: <Textarea id = "responseText" style = "width: 500px; height: 300px;"> </textarea>
</Form>
</Body>
</Html>
The logic of the above Javascript code is well understood: Create a Socket connection pointing to the corresponding WebSocket address (ws: // localhost: 8080/websocket), and then send and obtain the connection. In fact, we only need to place the websocket.html file on any HTTP server and open the corresponding URL address to see the following Demo interface:
Enter "Hello World" and click "Send Web Socket Data" to Send messages to the WebSocket server. We can also see that the returned message (uppercase hello world text) is displayed in the output box below "Receive", so that a basic information interaction is completed. Of course, if you close the server, the "Web Socket closed" information will be displayed in the output box.