基于netty的websocket开发小结
WebSocket是html5规范新引入的功能,用于解决浏览器与后台服务器双向通讯的问题,使用WebSocket技术,后台可以随时向前端推送消息,以保证前后台状态统一,在传统的无状态HTTP协议中,这是“无法做到”的。
WebSocket提出之前,为了解决后台推送消息到前台的需求,提出了一些解决方案,这些方案使用已有的技术(如ajax,iframe,flashplayer,java applet ...),通过一些变通的处理来实现。
webSocket是html5新引入的技术,允许后台随时向前端发送文本或者二进制消息,WebSocket是一种全新的协议,不属于http无状态协议,协议名为"ws",这意味着一个websocket连接地址会是这样的写法:
ws://127.0.0.1:8080/websocket。ws不是http,所以传统的web服务器不一定支持,需要服务器与浏览器同时支持, WebSocket才能正常运行,目前的支持还不普遍,需要特别的web服务器和现代的浏览器。
浏览器对WebSocket的支持
Google Chrome浏览器最先支持WebSocket,随后是Safari,Firefox,此外最新版本的Opera和IE(Opera11,IE10)也支持WebSocket。
客户端WebSocket的主要方法
1 构造函数
var websocket = new WebSocket("ws://127.0.0.1:8080/websocket");<!DOCTYPE html><html><head><script type="text/javascript" charset="utf-8" > window.WebSocket = window.WebSocket || window.MozWebSocket; if (!window.WebSocket){ alert("WebSocket not supported by this browser"); return; }; var websocket = new WebSocket("ws://127.0.0.1:8080/websocket"); websocket.onmessage = function(evt){ var data = evt.data; alert("received message: " + data); } function send() { var name = document.querySelector("input[name=name]").value; alert("websocket send message:"+name); websocket.send(name); }</script></head><body><label for="name">What’s your name:</label><input type="text" id="name" name="name" /><button onclick="send()">Send</button><div id="message" style="color:red"></div></body></html> private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception { // Allow only GET methods. if (req.getMethod() != GET) { sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN)); return; } // Send the demo page and favicon.ico if (req.getUri().equals("/")) { HttpResponse res = new DefaultHttpResponse(HTTP_1_1, OK); ChannelBuffer content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req)); res.setHeader(CONTENT_TYPE, "text/html; charset=UTF-8"); setContentLength(res, content.readableBytes()); res.setContent(content); sendHttpResponse(ctx, req, res); return; } else if (req.getUri().equals("/favicon.ico")) { HttpResponse res = new DefaultHttpResponse(HTTP_1_1, NOT_FOUND); sendHttpResponse(ctx, req, res); return; } // Handshake WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( this.getWebSocketLocation(req), null, false); this.handshaker = wsFactory.newHandshaker(req); if (this.handshaker == null) { wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.getChannel()); } else { this.handshaker.handshake(ctx.getChannel(), req); System.out.println(WebSocketServer.recipients.size()); WebSocketServer.recipients.add(ctx.getChannel()); System.out.println(WebSocketServer.recipients.size()); System.out.println(ctx.getChannel().getId()); } } private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) { // Check for closing frame if (frame instanceof CloseWebSocketFrame) { this.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())); } // Send the uppercase string back. String request = ((TextWebSocketFrame) frame).getText(); logger.debug(String.format("Channel %s received %s", ctx.getChannel().getId(), request));// WebSocketServer.recipients.write(new TextWebSocketFrame(request.toUpperCase())); ctx.getChannel().write(new TextWebSocketFrame(request.toUpperCase())); } public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { Object msg = e.getMessage(); if (msg instanceof HttpRequest) { handleHttpRequest(ctx, (HttpRequest) msg); } else if (msg instanceof WebSocketFrame) { handleWebSocketFrame(ctx, (WebSocketFrame) msg); } }package com.etao.mobile.websocket;import java.net.InetSocketAddress;import java.util.concurrent.Executors;import org.jboss.netty.bootstrap.ServerBootstrap;import org.jboss.netty.channel.group.ChannelGroup;import org.jboss.netty.channel.group.DefaultChannelGroup;import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;/** * A HTTP server which serves Web Socket requests at: * * http://localhost:8080/websocket * * Open your browser at http://localhost:8080/, then the demo page will be * loaded and a Web Socket connection will be made automatically. * * This server illustrates support for the different web socket specification * versions and will work with: * * <ul> * <li>Safari 5+ (draft-ietf-hybi-thewebsocketprotocol-00) * <li>Chrome 6-13 (draft-ietf-hybi-thewebsocketprotocol-00) * <li>Chrome 14+ (draft-ietf-hybi-thewebsocketprotocol-10) * <li>Chrome 16+ (RFC 6455 aka draft-ietf-hybi-thewebsocketprotocol-17) * <li>Firefox 7+ (draft-ietf-hybi-thewebsocketprotocol-10) * </ul> */public class WebSocketServer {private final int port;public static ChannelGroup recipients = new DefaultChannelGroup();public WebSocketServer(int port) {this.port = port;}public void run() {// Configure the server.ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));// Set up the event pipeline factory.bootstrap.setPipelineFactory(new WebSocketServerPipelineFactory());// Bind and start to accept incoming connections.bootstrap.bind(new InetSocketAddress(port));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();}}