1 packagewebsocket;2
3 importio.netty.buffer.ByteBuf;4 importio.netty.buffer.Unpooled;5 import io.netty.channel.*;6 import io.netty.handler.codec.http.*;7 import io.netty.handler.codec.http.websocketx.*;8 importio.netty.util.CharsetUtil;9
10 importjava.util.Date;11 importjava.util.logging.Level;12 importjava.util.logging.Logger;13
14 import staticio.netty.handler.codec.http.HttpHeaders.isKeepAlive;15 import staticio.netty.handler.codec.http.HttpHeaders.setContentLength;16
17 /**
18 * Created by lz on 2016/8/12.19 */
20 public class WebSocketServerHandler extends SimpleChannelInboundHandler{21 private static final Logger logger = Logger.getLogger(WebSocketServerHandler.class.getName());22
23 privateWebSocketServerHandshaker handshaker;24 @Override25 protected void messageReceived(ChannelHandlerContext ctx, Object msg) throwsException {26 //传统的HTTP接入
27 if (msg instanceofFullHttpRequest){28 handleHttpRequest(ctx,(FullHttpRequest)msg);29 }//WebSocket接入
30 else if (msg instanceofWebSocketFrame){31 handleWebSocketFrame(ctx,(WebSocketFrame)msg);32 }33 }34
35 private voidhandleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {36 //判断是否关闭链路指令
37 if (frame instanceofCloseWebSocketFrame){38 handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());39 return;40 }41 //判断是否是Ping消息
42 if (frame instanceofPingWebSocketFrame){43 ctx.channel().write(newPongWebSocketFrame(frame.content()).retain());44 return;45 }46 //本例程仅支持文本信息,不支持二进制消息
47 if (!(frame instanceofTextWebSocketFrame)){48 throw new UnsupportedOperationException(String.format("%s frame types not supported",frame.getClass().getName()));49 }50 //返回应答消息
51 String request =((TextWebSocketFrame) frame).text();52 if(logger.isLoggable(Level.FINE)){53 logger.fine(String.format("%s received %s",ctx.channel(),request));54 }55 ctx.channel().write(new TextWebSocketFrame(request+"欢迎使用Netty WebSocket服务,现在时刻:" + newDate().toString()));56 }57 private static voidsendHttpResponse(ChannelHandlerContext ctx,FullHttpRequest req,FullHttpResponse res){58 //返回应答给客户端
59 if (res.getStatus().code() != 200){60 ByteBuf buf =Unpooled.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8);61 res.content().writeBytes(buf);62 buf.release();63 setContentLength(res,res.content().readableBytes());64 }65 //如果是非Keep-Alive,关闭连接
66 ChannelFuture f =ctx.channel().writeAndFlush(res);67 if (!isKeepAlive(req) || res.getStatus().code() != 200){68 f.addListener(ChannelFutureListener.CLOSE);69 }70 }71
72
73 private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) throwsException{74 //如果HTTP解码失败,返回HTTP异常
75 if (!req.getDecoderResult().isSuccess()76 || (!"websocket".equals(req.headers().get("Upgrade")))){77 sendHttpResponse(ctx,req,newDefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));78 return;79 }80 //构造握手响应返回,本机测试
81 WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory("ws://localhost:8080/websocket",null,false);82 handshaker =wsFactory.newHandshaker(req);83 if (handshaker == null){84 WebSocketServerHandshakerFactory.sendUnsupportedWebSocketVersionResponse(ctx.channel());85 }else{86 //把握手消息返回给客户端
87 handshaker.handshake(ctx.channel(),req);88 }89 }90
91
92 @Override93 public void channelReadComplete(ChannelHandlerContext ctx) throwsException {94 ctx.flush();95 }96
97 @Override98 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throwsException {99 cause.printStackTrace();100 ctx.close();101 }102 }