使用浏览器访问服务端,返回消息给前台展示,Netty做Http服务需要指定编码解码器
每个客户端对应一个Channel,其 PipeLine 和 Handler 都是独享的
服务端代码:
package http;import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.nio.NioServerSocketChannel;public class MyServer {public static void main(String[] args) throws Exception {/* 创建 BossGroup 和 WorkerGroup 线程组* BossGroup 只处理连接请求,真正的和客户端业务处理会交给 WorkGrouop 完成* bossGroup 和 workerGroup 含有的子线程的个数默认为 CPU最大线程数 X 2,可以手动指定*/EventLoopGroup bossGroup = new NioEventLoopGroup(1); //创建子线程的个数为1的 bossGroupEventLoopGroup workerGroup = new NioEventLoopGroup(8); //创建子线程的个数为8的 workerGrouptry{ServerBootstrap serverBootstrap = new ServerBootstrap();serverBootstrap.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).childHandler(new ServerInitializer()); //一个客户端对应一个PipeLine和一个Handler,PipeLine和Handler是独享的ChannelFuture sync = serverBootstrap.bind(6668).sync();sync.channel().closeFuture().sync(); //对关闭通道进行监听(当有关闭通道的消息时才进行监听)} finally {bossGroup.shutdownGracefully(); //关闭资源workerGroup.shutdownGracefully(); //关闭}}}
自定义管道Handler:
package http;import io.netty.buffer.ByteBuf;import io.netty.buffer.Unpooled;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.SimpleChannelInboundHandler;import io.netty.handler.codec.http.*;import io.netty.util.CharsetUtil;import java.net.URI;/** 1. SimpleChannelInboundHandler 是 ChannelInboundHandlerAdapter 的子类* 2. 客户端和服务器端相互通讯的数据被封装为 HttpObject** */public class MyHttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {/* 读取客户端数据 */@Overrideprotected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {//判断msg是不是HttpRequest请求if(msg instanceof HttpRequest){System.out.println("msg类型="+msg.getClass());System.out.println("客户端地址:"+ctx.channel().remoteAddress());System.out.println("当前的PipeLine HashCode是: "+ctx.pipeline().hashCode()+" ;当前的ServerHandler HashCode是: "+this.hashCode());//获取请求头,由于浏览器会请求网站ICO图标,服务端会将其当做请求,需要进行剔除HttpRequest httpRequest = (HttpRequest) msg;URI uri = new URI(httpRequest.uri());if("/favicon.ico".equals(uri.getPath())){System.out.println("浏览器请求了网站ICO,不响应");return;}//回复信息给浏览器(需要Http协议)ByteBuf content = Unpooled.copiedBuffer("hello,我是服务器", CharsetUtil.UTF_8);//创建Http响应并设置头DefaultFullHttpResponse 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());//将构建好的response返回ctx.writeAndFlush(response);}}}
服务端初始化Handler:
package http;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelPipeline;import io.netty.channel.socket.SocketChannel;import io.netty.handler.codec.http.HttpServerCodec;/* 服务端初始化Handler */public class ServerInitializer extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline(); //得到管道pipeline.addLast("MyHttpServerCodec",new HttpServerCodec()); //向管道加入Netty提供的 HttpServerCodec(编码&解码器)pipeline.addLast("MyHttpServerHandler",new MyHttpServerHandler()); //添加一个自定义的Handler}}
测试:
使用两个浏览器访问,可以看到每个客户端其Channel对应的 PipeLine 和 Handler 都是自己独享的
多浏览器访问测试

浏览器默认会请求网站ICO图标,服务端屏蔽后不返回响应结果
