赞
踩
咱们的学习思路比较奇特,看到啥学啥。
先将为什么要用Websocker.因为Http只能由客户端发送给服务端。而没办法相互通信,而Websocker解决了这个问题。
那Spring boot有自带的WebSocker集成,那为啥不用呢?因为Netty比较牛逼(建议自行百度)。本人理解就是,它可以变成所有的协议服务,用自定义的操作很方便又简易的开发方式,Netty成功地找到了一种在不妥协的情况下实现易于开发,性能,稳定性和灵活性的方法。
这里只做服务器的代码,客户端的测试,可以去找一下测试工具!!!
你可以偷偷用,不要告诉别人喔~
好,然后到了我们的实现步骤,
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.21.Final</version>
</dependency>
/** * @author * * netty服务初始化器 * 主要是配置业务的前置信息 * 比如像和客户端通信,指定相应的通信协议,编码解码信息,自定义相关的handler **/ public class NettyServerChannelInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { //添加编解码 socketChannel.pipeline().addLast(new HttpServerCodec()); //添加对于读写大数据流的支持 socketChannel.pipeline().addLast(new ChunkedWriteHandler()); //对httpMessage进行聚合 socketChannel.pipeline().addLast(new HttpObjectAggregator(1024*64)); // WebSocketServerProtocolHandler:将 http 协议升级为 ws 协议,保持长连接 socketChannel.pipeline().addLast(new WebSocketServerProtocolHandler("/ws")); // 增加IdleStateHandler心跳检测处理器,userEventTriggered()方法作为超时事件,如果五秒内ChannelRead()方法未被调用 socketChannel.pipeline().addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS)); //增加一个自己的Handler操作 socketChannel.pipeline().addLast(new NettyServerHandler()); } }
可以在代码看到,里面添加了很多类进去,注意倒数三个,一个是将http变成Websock,一个是心跳检测器,是哪个参数分别对应,客户端的写操作超时时间,读操作超时时间,全部操作超时时间,第三个是我们自定义的业务Handler。埋个伏笔(关于编解码的问题,只知道概念,不知道会有什么影响…)
/** * @author * * WebSocketFrame: 表示一个文本帧 * netty服务端处理器 **/ public class NettyServerHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = LoggerFactory.getLogger(NettyServerHandler.class); /** * 客户端连接会触发 */ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { logger.info("Channel active......"); } /** * 客户端发消息会触发 */ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { logger.info("服务器收到消息: {}", msg.toString()); if (msg instanceof TextWebSocketFrame) { TextWebSocketFrame textMsg = (TextWebSocketFrame) msg; logger.info("服务器收到文本消息: {}", textMsg.text()); } //ctx.channel().write(new TextWebSocketFrame("abc")); ctx.flush(); } /** * 发生异常触发 */ @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } //客户端销毁的时候触发, @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { //当handlerRemoved 被触发时候,channelGroup会自动移除对应的channel //clients.remove(ctx.channel()); System.out.println("客户端断开,当前被移除的channel的短ID是:" + ctx.channel().id().asShortText()); } private int lossConnectCount = 0; @Override public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception { if (obj instanceof IdleStateEvent) { IdleStateEvent event = (IdleStateEvent) obj; //这就是客户端不写过来 if (event.state() == IdleState.READER_IDLE) { logger.info("客户端写超时"); lossConnectCount++; if(lossConnectCount > 2){ logger.info("关闭这个不活跃的通道"); ctx.channel().close(); } //这是客户端不读 } else if (event.state() == IdleState.WRITER_IDLE) { logger.info("客户端读超时"); //如果都没操作就都无 } else if (event.state() == IdleState.ALL_IDLE) { logger.info("客户端所有操作超时"); } } } }
重点都在注释里面了。。我就不讲解了
新建NettyServer类
/** * @author * <p> * 服务启动监听器 **/ public class NettyServer { private static final Logger logger = LoggerFactory.getLogger(NettyServerHandler.class); public void start(InetSocketAddress socketAddress) { //new 一个主线程组 EventLoopGroup bossGroup = new NioEventLoopGroup(1); //new 一个工作线程组 EventLoopGroup workGroup = new NioEventLoopGroup(200); ServerBootstrap bootstrap = new ServerBootstrap() .group(bossGroup, workGroup) //设置通道 .channel(NioServerSocketChannel.class) //设置子处理器 .childHandler(new NettyServerChannelInitializer()) .localAddress(socketAddress) //设置队列大小 .option(ChannelOption.SO_BACKLOG, 1024) // 两小时内没有数据的通信时,TCP会自动发送一个活动探测数据报文 .childOption(ChannelOption.SO_KEEPALIVE, true); //绑定端口,开始接收进来的连接 try { ChannelFuture future = bootstrap.bind(socketAddress).sync(); logger.info("服务器启动开始监听端口: {}", socketAddress.getPort()); future.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { //关闭主线程组 bossGroup.shutdownGracefully(); //关闭工作线程组 workGroup.shutdownGracefully(); } } }
在启动类里面加入这个方法
public static void main(String[] args) {
SpringApplication.run(DevApplication.class, args);
//1.判断库是否存在
//2.建库.
//3.判断表是否存在,不存在建立表,存在则更新数据库表结构
//4.表建立完之后,进行外键的连接。
//启动服务端
NettyServer nettyServer = new NettyServer();
nettyServer.start(new InetSocketAddress("172.31.97.13", 6088));
}
我们来看看结果
Nice,Bro
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。