java Netty WebSocketServer

下载官方示例
netty官方 github
官方WebSocket相关演示文档路径:
在这里插入图片描述

看了下几乎和DotNetty的一模一样。(好歹DotNetty是大部分是照着仿写的)

在此基础上修改使用:
NettyWebSocketServer
两个事件循环组,bossGroup和workerGroup,绑定后增加日志handler,为通道Channel指定处理handler(WebSocketServerInitializer)
和官方示例比,图省事,把ssl给删掉了,参数直接给了个Null

package com.SocketLayer.WebSocketServer;

import java.util.HashMap;

import com.Global.LogManager;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

public class NettyWebSocketServer {

	public static void StartListening(int PORT) {
		EventLoopGroup bossGroup = new NioEventLoopGroup(1);
		EventLoopGroup workerGroup = new NioEventLoopGroup();
		try {
			ServerBootstrap b = new ServerBootstrap();
			b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
					.handler(new LoggingHandler(LogLevel.INFO)).childHandler(new WebSocketServerInitializer(null));

			Channel ch = b.bind(PORT).sync().channel();
			ch.closeFuture().sync();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			LogManager.writeError(e);
		} finally {
			bossGroup.shutdownGracefully();
			workerGroup.shutdownGracefully();
		}
	}

	private static HashMap<String, Channel> ClientMap = new HashMap<>();

	public static void ClientRegist(Channel c) {
		ClientMap.put(c.remoteAddress().toString(), c);
	}

	public static void ClientUnRegist(Channel c) {
		ClientMap.remove(c.remoteAddress().toString());
	}
}

WebSocketServerInitializer
初始化及在管道队列中添加对应的Handler(绑定)
HttpServerCodec:
Creates a new instance with the default decoder options (maxInitialLineLength (4096}, maxHeaderSize (8192), and maxChunkSize (8192)).
默认的decoder(编码器)
HttpObjectAggregator:
指定单次消息的最大长度
WebSocketServerCompressionHandler:
Constructor with default configuration.
(默认配置)
WebSocketServerProtocolHandler:
WebSocketServer协议处理
WebSocketIndexPageHandler:
握手请求处理(名字忘了改,直接用了官方示例的名字)
WebSocketFrameHandler:
WebSocket帧处理

package com.SocketLayer.WebSocketServer;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler;
import io.netty.handler.ssl.SslContext;

/**
 */
public class WebSocketServerInitializer extends ChannelInitializer<SocketChannel> {

	private static final String WEBSOCKET_PATH = "/websocket";

	private final SslContext sslCtx;

	public WebSocketServerInitializer(SslContext sslCtx) {
		this.sslCtx = sslCtx;
	}

	@Override
	public void initChannel(SocketChannel ch) throws Exception {
		ChannelPipeline pipeline = ch.pipeline();
		if (sslCtx != null) {
			pipeline.addLast(sslCtx.newHandler(ch.alloc()));
		}
		pipeline.addLast(new HttpServerCodec());
		pipeline.addLast(new HttpObjectAggregator(65536));
		pipeline.addLast(new WebSocketServerCompressionHandler());
		pipeline.addLast(new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true));
		pipeline.addLast(new WebSocketIndexPageHandler(WEBSOCKET_PATH));
		pipeline.addLast(new WebSocketFrameHandler());
	}
}

WebSocketIndexPageHandler

package com.SocketLayer.WebSocketServer;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
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.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.ssl.SslHandler;
import io.netty.util.CharsetUtil;

import static io.netty.handler.codec.http.HttpHeaderNames.*;
import static io.netty.handler.codec.http.HttpMethod.*;
import static io.netty.handler.codec.http.HttpResponseStatus.*;

/**
 * Outputs index page content.
 */
public class WebSocketIndexPageHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

	private final String websocketPath;

	public WebSocketIndexPageHandler(String websocketPath) {
		this.websocketPath = websocketPath;
	}

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {
		// Handle a bad request.
		if (!req.decoderResult().isSuccess()) {
			sendHttpResponse(ctx, req,
					new DefaultFullHttpResponse(req.protocolVersion(), BAD_REQUEST, ctx.alloc().buffer(0)));
			return;
		}

		// Allow only GET methods.
		if (!GET.equals(req.method())) {
			sendHttpResponse(ctx, req,
					new DefaultFullHttpResponse(req.protocolVersion(), FORBIDDEN, ctx.alloc().buffer(0)));
			return;
		}

		// Send the index page
		if ("/".equals(req.uri()) || "/index.html".equals(req.uri())) {
			String webSocketLocation = getWebSocketLocation(ctx.pipeline(), req, websocketPath);
			ByteBuf content = Unpooled.copiedBuffer(webSocketLocation + ": welcome", CharsetUtil.US_ASCII);
			FullHttpResponse res = new DefaultFullHttpResponse(req.protocolVersion(), OK, content);

			res.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8");
			HttpUtil.setContentLength(res, 0);

			sendHttpResponse(ctx, req, res);
		} else {
			sendHttpResponse(ctx, req,
					new DefaultFullHttpResponse(req.protocolVersion(), NOT_FOUND, ctx.alloc().buffer(0)));
		}
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
		cause.printStackTrace();
		ctx.close();
	}

	private static void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) {
		// Generate an error page if response getStatus code is not OK (200).
		HttpResponseStatus responseStatus = res.status();
		if (responseStatus.code() != 200) {
			ByteBufUtil.writeUtf8(res.content(), responseStatus.toString());
			HttpUtil.setContentLength(res, res.content().readableBytes());
		}
		// Send the response and close the connection if necessary.
		boolean keepAlive = HttpUtil.isKeepAlive(req) && responseStatus.code() == 200;
		HttpUtil.setKeepAlive(res, keepAlive);
		ChannelFuture future = ctx.writeAndFlush(res);
		if (!keepAlive) {
			future.addListener(ChannelFutureListener.CLOSE);
		}
	}

	private static String getWebSocketLocation(ChannelPipeline cp, HttpRequest req, String path) {
		String protocol = "ws";
		if (cp.get(SslHandler.class) != null) {
			// SSL in use so use Secure WebSockets
			protocol = "wss";
		}
		return protocol + "://" + req.headers().get(HttpHeaderNames.HOST) + path;
	}
}

WebSocketFrameHandler

package com.SocketLayer.WebSocketServer;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;

import java.util.Locale;

import com.Model.ExpressionPack.ExpressionCMD;
import com.TVSensoranalyzerj.RegulationPackManager;
import com.alibaba.fastjson.JSON;

/**
 * Echoes uppercase content of text frames.
 */
public class WebSocketFrameHandler extends SimpleChannelInboundHandler<WebSocketFrame> {

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {
		// ping and pong frames already handled

		if (frame instanceof TextWebSocketFrame) {
			// Send the uppercase string back.
			String request = ((TextWebSocketFrame) frame).text();
			try {
				ExpressionCMD cmd = JSON.parseObject(request, ExpressionCMD.class);
				switch (cmd.getMsgType().toLowerCase()) {
				case "loadrootstr":
					var rootStr = RegulationPackManager.getRootStr();
					ctx.channel().writeAndFlush(new TextWebSocketFrame(rootStr));
					break;
				case "updateexpression":
				case "deleteexpression":
				case "updatedeviced":
				case "deletedeviced":
					if (RegulationPackManager.getMode() != 0) {
						cmd.setContext("Error: Invalid Operate during Mode" + RegulationPackManager.getMode());
						ctx.channel().writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(cmd)));
						break;
					}
					cmd.setMsgType(cmd.getMsgType() + "_ACK");
					if (RegulationPackManager.HandleCmd(cmd))
						ctx.channel().writeAndFlush(new TextWebSocketFrame(RegulationPackManager.getRootStr()));
					else
						ctx.channel().writeAndFlush(new TextWebSocketFrame("error"));
					break;

				}
			} catch (Exception e) {
				// TODO: handle exception
				ctx.channel().writeAndFlush(new TextWebSocketFrame("InValid CMD"));
			}

			ctx.channel().writeAndFlush(new TextWebSocketFrame(request.toUpperCase(Locale.US)));
		} else {
			String message = "unsupported frame type: " + frame.getClass().getName();
			throw new UnsupportedOperationException(message);
		}
	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		// TODO Auto-generated method stub
		super.channelRead(ctx, msg);
	}

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		// TODO Auto-generated method stub
		super.channelActive(ctx);
		NettyWebSocketServer.ClientRegist(ctx.channel());
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		// TODO Auto-generated method stub
		super.channelInactive(ctx);
		NettyWebSocketServer.ClientUnRegist(ctx.channel());
	}
}

效果:
在这里插入图片描述在这里插入图片描述感觉都不想费过多口舌了,发现官方上的github里啥都有,很详细,然后还有example,很适合懒人。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值