|
@@ -0,0 +1,113 @@
|
|
|
+package com.jd.cms.nettySocket;
|
|
|
+
|
|
|
+import cn.hutool.core.date.DateUtil;
|
|
|
+import cn.hutool.json.JSONObject;
|
|
|
+import cn.hutool.json.JSONUtil;
|
|
|
+import io.netty.buffer.ByteBuf;
|
|
|
+import io.netty.buffer.Unpooled;
|
|
|
+import io.netty.channel.ChannelFuture;
|
|
|
+import io.netty.channel.ChannelHandlerContext;
|
|
|
+import io.netty.channel.SimpleChannelInboundHandler;
|
|
|
+import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
|
|
+import io.netty.handler.codec.http.FullHttpRequest;
|
|
|
+import io.netty.handler.codec.http.HttpResponseStatus;
|
|
|
+import io.netty.handler.codec.http.HttpVersion;
|
|
|
+import io.netty.handler.codec.http.websocketx.*;
|
|
|
+import io.netty.util.CharsetUtil;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
+public class NioWebSocketHandler extends SimpleChannelInboundHandler<Object> {
|
|
|
+
|
|
|
+ private WebSocketServerHandshaker handshaker;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
|
|
|
+ //log.info("收到消息" + msg);
|
|
|
+ if (msg instanceof FullHttpRequest) {
|
|
|
+ //以http请求形式接入,但是走的是websocket
|
|
|
+ handleHttpRequest(ctx, (FullHttpRequest) msg);
|
|
|
+ } else if (msg instanceof WebSocketFrame) {
|
|
|
+ //处理websocket客户端的消息
|
|
|
+ handlerWebSocketFrame(ctx, (WebSocketFrame) msg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
|
|
+ //添加连接
|
|
|
+ log.info("客户端加入连接:" + ctx.channel());
|
|
|
+ ChannelManage.addChannel(ctx.channel());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
|
|
+ //断开连接
|
|
|
+ log.info("客户端断开连接:" + ctx.channel());
|
|
|
+ ChannelManage.removeChannel(ctx.channel());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
|
|
|
+ ctx.flush();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handlerWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
|
|
|
+ // 判断是否关闭链路的指令
|
|
|
+ if (frame instanceof CloseWebSocketFrame) {
|
|
|
+ handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 判断是否ping消息
|
|
|
+ if (frame instanceof PingWebSocketFrame) {
|
|
|
+ ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 判断是不是文本消息,不是文本抛异常
|
|
|
+ if (!(frame instanceof TextWebSocketFrame)) {
|
|
|
+ throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass().getName()));
|
|
|
+ }
|
|
|
+ // 把服务器收到的消息发送到每个通道
|
|
|
+ String request = ((TextWebSocketFrame) frame).text();
|
|
|
+ log.info("服务端收到:" + request);
|
|
|
+ //封装消息主体
|
|
|
+ JSONObject msg = JSONUtil.createObj()
|
|
|
+ .set("date", DateUtil.now())
|
|
|
+ .set("msg", request);
|
|
|
+ TextWebSocketFrame tws = new TextWebSocketFrame(msg.toString());
|
|
|
+ // 群发,把当前通道传过去,那边排除掉
|
|
|
+ ChannelManage.send2All(tws, ctx.channel().id());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 唯一的一次http请求,用于创建websocket
|
|
|
+ */
|
|
|
+ private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {
|
|
|
+ //要求Upgrade为websocket,过滤掉get/Post
|
|
|
+ if (!req.decoderResult().isSuccess() || (!"websocket".equals(req.headers().get("Upgrade")))) {
|
|
|
+ //若不是websocket方式,则创建BAD_REQUEST的req,返回给客户端
|
|
|
+ sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ //WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory("ws://192.168.0.114:8088/websocket", null, true);
|
|
|
+ handshaker = new WebSocketServerHandshaker13("ws://23.37.100.81:8088/websocket", null, true, 1024 * 1024 * 6);
|
|
|
+ if (handshaker == null) {
|
|
|
+ WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
|
|
|
+ } else {
|
|
|
+ handshaker.handshake(ctx.channel(), req);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 拒绝不合法的请求,并返回错误信息
|
|
|
+ */
|
|
|
+ private void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, DefaultFullHttpResponse res) {
|
|
|
+ // 返回应答给客户端
|
|
|
+ if (res.status().code() != 200) {
|
|
|
+ ByteBuf buf = Unpooled.copiedBuffer(res.status().toString(), CharsetUtil.UTF_8);
|
|
|
+ res.content().writeBytes(buf);
|
|
|
+ buf.release();
|
|
|
+ }
|
|
|
+ ChannelFuture f = ctx.channel().writeAndFlush(res);
|
|
|
+ }
|
|
|
+}
|