使用netty建立websocket进行群聊

作者 chauncy 日期 2016-12-09
使用netty建立websocket进行群聊

WebSocket 简介:

WebSocket 规范定义了一种 API,可在网络浏览器和服务器之间建立“套接字”连接。简单地说:客户端和服务器之间存在持久的连接,而且双方都可以随时开始发送数据。

第一次请求客户端发送的是http请求,请求头中包含websocket相关的信息,服务器端对请求进行验证,所以要添加一些http 的解码编码handler,同时也要添加WebSocket 的handler处理器,如下:

public class ChildChannelHandler extends ChannelInitializer<SocketChannel> {


@Override
protected void initChannel(SocketChannel ch) throws Exception {
  ch.pipeline().addLast("decoder", new HttpRequestDecoder());   //用于解析http报文的handler
  ch.pipeline().addLast("aggregator", new HttpObjectAggregator(65536));   //用于将解析出来的数据封装成http对象,httprequest什么的
  ch.pipeline().addLast("encoder", new HttpResponseEncoder());   //用于将response编码成httpresponse报文发送
  ch.pipeline().addLast("handshake", new WebSocketServerProtocolHandler("", "", true));  //websocket的handler部分定义的,它会自己处理握手等操作
  ch.pipeline().addLast("handler", new MyWebSocketServerHandler());
}
}

第一次处理的事http 请求,等到建立WebSocket 之后就需要处理WebSocket的请求,如下代码:

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof FullHttpRequest) {

            handleHttpRequest(ctx, ((FullHttpRequest) msg));

        } else if (msg instanceof WebSocketFrame) {

            handlerWebSocketFrame(ctx, (WebSocketFrame) msg);

        }
    }

接下来告诉客户端,接下来的数据按照websocket协议来发送内容了,以及启动websocket服务器在制定的端口上

private void handleHttpRequest(ChannelHandlerContext ctx,
                                   FullHttpRequest req) {

        if (!req.getDecoderResult().isSuccess()
                || (!"websocket".equals(req.headers().get("Upgrade")))) {

            sendHttpResponse(ctx, req, new DefaultFullHttpResponse(
                    HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));

            return;
        }

        WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
                "ws://localhost:8888/websocket", null, false);

        handshaker = wsFactory.newHandshaker(req);

        if (handshaker == null) {
            WebSocketServerHandshakerFactory
                    .sendUnsupportedVersionResponse(ctx.channel());
        } else {
            handshaker.handshake(ctx.channel(), req);
        }

    }

最后,在读取到消息时websocket类型过后,将消息进行群发

private void handlerWebSocketFrame(ChannelHandlerContext ctx,
                                     WebSocketFrame frame) {


      // 返回应答消息
      String request = ((TextWebSocketFrame) frame).text();

      System.out.println("recv:" + request);


      TextWebSocketFrame tws = new TextWebSocketFrame(new Date().toString()
              + ctx.channel().localAddress() + ":" + request);

      // 群发
      MyChannelGroup.group.writeAndFlush(tws);


  }

代码地址