我这次是按照NIO模型编写的一个服务端
public class HelloServer { public static void main(String[] args) throws Exception { //定义一对线程组 //主线程组,用于接收客户端的连接,但是不做任何处理,跟老板一样,不做事 EventLoopGroup bossGroup=new NioEventLoopGroup(); //从线程组,老板线程组会把任务丢给她,让手下线程组去做任务 EventLoopGroup workerGroup=new NioEventLoopGroup(); try { //netty服务器的创建,ServerBootstrap 是一个启动类 ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup, workerGroup) //设置主从线程组 .channel(NioServerSocketChannel.class) //设置nio的双向通道 .childHandler(new HelloServerInitializer()); //子处理器,用于处理workerGroup //启动server,并且设置8088为启动的端口号,同时启动方式为同步 ChannelFuture channelFuture = serverBootstrap.bind(8088).sync(); //监听关闭的channel,设置位同步方式 channelFuture.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); }finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } } 复制代码
NIO模型中,服务端有两个线程组,一个线程组是用来完成客户端到服务端连接的,另一个线程组是用来处理IO操作的,通过ServerBootstrap这个类的实例绑定在一起。
//初始化器,channel注册后,会执行里面的相应的初始化方式 public class HelloServerInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel channel) throws Exception { //通过Socketchannel去获取对应的管道 ChannelPipeline pipeline=channel.pipeline(); //通过管道 //HttpSeverCodec是由netty自己提供的助手类,可以理解为拦截器 //当请求到服务端,我们需要做解码,响应到客户端做编码 pipeline.addLast("HttpServerCodec",new HttpServerCodec()); //添加自定义的助手类,返回"hello netty~" pipeline.addLast("customHandler",new CustomHandler()); } } 复制代码
//创建自定义助手类 //SimpleChannelInboundHandler:对于请求来讲,相当于【入栈,出栈】 public class CustomHandler extends SimpleChannelInboundHandler<HttpObject> { @Override protected void channelRead0(ChannelHandlerContext ctx, HttpObject httpObject) throws Exception { // 获取channel Channel channel=ctx.channel(); if(httpObject instanceof HttpRequest){ // 显示客户端的远程地址 System.out.println(channel.remoteAddress()); // copiedBuffer在JVM中创建一块缓冲区适用于深拷贝缓冲区的 ByteBuf content= Unpooled.copiedBuffer("Hello chenhao~", CharsetUtil.UTF_8); // 创建一个http response FullHttpResponse response= new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content); //为响应增加数据类型和长度 response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain"); response.headers().set(HttpHeaderNames.CONTENT_LENGTH,content.readableBytes()); //把响应刷到客户端 ctx.writeAndFlush(response); } } @Override public void channelRegistered(ChannelHandlerContext ctx) throws Exception { System.out.println("channel...注册"); super.channelRegistered(ctx); } @Override public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { System.out.println("channel...移除"); super.channelUnregistered(ctx); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { System.out.println("channel...活跃"); super.channelActive(ctx); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { System.out.println("channel...不活跃"); super.channelInactive(ctx); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { System.out.println("channel读取完毕..."); super.channelReadComplete(ctx); } @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { System.out.println("channel用户事件触发..."); super.userEventTriggered(ctx, evt); } @Override public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception { System.out.println("channel可写更改..."); super.channelWritabilityChanged(ctx); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { System.out.println("捕获到异常"); super.exceptionCaught(ctx, cause); } @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { System.out.println("助手类添加"); super.handlerAdded(ctx); } @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { System.out.println("助手类移除"); super.handlerRemoved(ctx); } } 复制代码