注:使用netty之前,需要先引入netty包,不同的框架,引入netty包的方式不同
1.定义NettyServer类
用于初始化netty连接
public class NettyServer {public void start() throws Exception {System.out.println("启动记载netty");EventLoopGroup boosGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();ServerBootstrap serverBootstrap = new ServerBootstrap(); // 引导类ServerBootstrap,这个类将引导服务端的启动工作serverBootstrap.group(boosGroup, workerGroup) // .group(bossGroup,workerGroup)给引导类配置两大线程组.channel(NioServerSocketChannel.class) // 指定服务端的IO模型为NIO NioServerSocketChannel是对NIO类型连接的抽象.option(ChannelOption.SO_BACKLOG, 1024) // 表示系统用于临时存放已完成三次握手的请求的队列的最大长度.childOption(ChannelOption.SO_KEEPALIVE, true) // 表示是否开启TCP底层心跳机制,true表示开启。.childOption(ChannelOption.TCP_NODELAY, true) // 表示是否开启Nagle算法,true表示关闭,false表示开启.handler(new ChannelInitializer<NioServerSocketChannel>() { // handler()方法用于指定在服务端启动过程中的一些逻辑@Overrideprotected void initChannel(NioServerSocketChannel ch) {System.out.println("服务端启动过程中...");}}).childHandler(new ChannelInitializer<NioSocketChannel>() { // childHandler()方法,给这个引导类创建一个ChannelInitializer,主要是定义后续每个连接的数据读写protected void initChannel(NioSocketChannel ch) { // 泛型参数NioSocketChannel,这个类就是Netty对NIO类型连接的抽象ch.pipeline().addLast(new IdleStateHandler(0, 0, 15));//检测读写空闲事件,需要就开启,不需要就关闭ch.pipeline().addLast(new EchoServerHandler());}});System.out.println("启动加载netty2");// 给这个ChannelFuture添加一个监听器GenericFutureListenerserverBootstrap.bind(9997).addListener(future -> {if (future.isSuccess()) {System.out.println(new Date() + ": 端口[" + 9997 + "]绑定成功!");} else {System.err.println("端口[" + 9997 + "]绑定失败!");}});}
}
2.编写EchoServerHandler
用于netty接收到数据后处理数据
public class EchoServerHandler extends ChannelInboundHandlerAdapter {/*** 读取客户端发送过来的数据* @param ctx 上下文对象* @param msg 客户端发送的数据* @throws Exception*/@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg){ByteBuf byteBuf= (ByteBuf) msg;String req=byteBuf.toString(CharsetUtil.UTF_8);System.out.println("接收到客户端请求:"+req);System.out.println("客户端地址: " + ctx.channel().remoteAddress());/**String res= "服务器响应["+ LocalDateTime.now().format(DateTimeFormatter.ISO_DATE)+" "+LocalDateTime.now().format(DateTimeFormatter.ISO_TIME)+"]:"+req;System.out.println("服务端响应:"+res);**/}/*** 数据读取完毕* @param ctx* @throws Exception*/@Overridepublic void channelReadComplete(ChannelHandlerContext ctx){ctx.writeAndFlush(Unpooled.copiedBuffer("服务器响应[收到消息,谢谢]",CharsetUtil.UTF_8));}/*** 处理异常, 一般是需要关闭通道* @param ctx* @param cause* @throws Exception*/@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause){cause.printStackTrace();ctx.close();}@Overridepublic void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {if (evt instanceof IdleStateEvent) {IdleStateEvent event = (IdleStateEvent) evt;if (event.state() == IdleState.WRITER_IDLE) {ctx.channel().writeAndFlush("Heartbeat" + System.getProperty("line.separator"));}else if(event.state() == IdleState.ALL_IDLE){//如果长时间空闲,则关闭链接System.out.println("链接长时间没有数据,关闭连接");ctx.channel().close();}}}
}
3.使用netty
public class Main {public static void main(String[] args) {NettyServer server = new NettyServer();try{server.start();}catch (Exception e) {throw new RuntimeException(e);}}
}