下载官方示例
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,很适合懒人。。