netty学习(一) - helloWorld

4 篇文章 0 订阅

钻石恒久远,helloWorld 永流传。作为第一个netty的入门程序,也来写一个基于netty实现的helloWorld,直接上代码

服务器代码

public class HttpServer {

    public static void main(String[] args) throws InterruptedException {
        // acceptor 使用的线程池 它只处理连接请求 不做具体的工作 所以叫boss
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        // 真正执行业务的线程池,针对于boss 它就是worker
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            // 定义一个服务器启动
            ServerBootstrap bootstrap = new ServerBootstrap()
                    // 给服务指定工作线程池 此处采用构建者模式
                    .group(bossGroup, workerGroup)
                    // 指定使用的通道类型尾nio的服务器通道
                    .channel(NioServerSocketChannel.class)
                    // 指定一个通道处理器,也就是第一次请求过来了,需要建立长连接的时候做干些什么
                    .childHandler(new HttpServerChannelInitializer());
            // 异步的去绑定一个端口号
            ChannelFuture channelFuture = bootstrap.bind(18888).sync();

            // 异步的关闭通道
            channelFuture .channel().closeFuture().sync();
        }finally {
            // 使用netty提供的api 关闭线程池  Gracefully-> 优雅的 温柔的
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }
}

服务器通道初始化器

public class HttpServerChannelInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        // 获取管道 pipeline 是一个很重要的概念,在tomcat的容器部分同样使用了pipeline,它体现了责任分发的思想
        ChannelPipeline pipeline = ch.pipeline();
        // 添加一个针对于http的通道处理器
        pipeline.addLast("httpServerCodec", new HttpServerCodec());
        // 添加一个自定义的处理器 针对于每一个通道(连接) 都应该指定一个新的处理器,这个处理器不能是单例的 因为netty里面很多并发支持
        pipeline.addLast("httpServerChannelHandler", new HttpServerChannelHandler());
    }
}

通道处理器

public class HttpServerChannelHandler extends SimpleChannelInboundHandler<HttpObject> {

    private static final Logger logger = LoggerFactory.getLogger(HttpServerChannelHandler.class);

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
        // 获取请求的消息
        if (msg instanceof HttpRequest) {
            HttpRequest request = (HttpRequest) msg;
            // 打印当前请求的url和方法
            logger.info("url:{},method:{}", request.uri(), request.method());
            // 构建一个netty独有的字节流对象
            ByteBuf content = Unpooled.copiedBuffer("hello world!", CharsetUtil.UTF_8);
            // 构建一个响应对象
            HttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content);
            // 设置响应内容的长度
            response.headers().add(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());
            // 设置内容类型
            response.headers().add(HttpHeaderNames.CONTENT_TYPE, "text/plain");
            // write 只是将数据写到了缓冲区,所以需要flush一下
            ctx.writeAndFlush(response);
        }
    }
}


编写完成后直接启动HttpServer中的main方法 ,然后打开浏览器 输入:http://localhost:18888即可看到
效果
在这里插入图片描述

总结

概念解释
initializer初始化器,客户端成功连接到服务端的时候会触发初始化器中的初始化回调方法
channel通道(连接),与io流的区别是io流是单向,但是通道是双向的,也就是通道既可以接收,又可以发送
channelHandler通道处理器,服务器/客户端收到消息的时候作出相应的处理
pipeline 管道用来装载channelHandler的容器
inbound入站,处理请求数据
outbound出站,处理响应数据
bossGroup服务器端处理请求连接的线程池,又叫 parentGroup
workerGroup服务器端真正处理请求的线程池, 又叫 childGroup

为什么ServerBootstrap要使用2个线程池

因为bossGroup 负责处理请求的连接,workerGroup 负责处理业务,如果使用一个线程池,当并发量高的时候会出现不能够及时处理连接的情况

ServerBootstrap中的childHandler 和 handler方法有什么区别

childHandler 提供给workerGroup中的线程使用
handler  提供给bossGroup中的线程使用,

sync()

标志该动作执行完毕之后再继续执行下面的代码,如果动作尚未执行完毕,则阻塞当前线程
>  bootstrap.bind(18888).sync() // 当操作系统的端口被成功绑定 才会继续执行下面代码,否则阻塞
>   channelFuture .channel().closeFuture().sync() // 当连接通道被成功关闭的时候才会继续往下执行

为什么netty 不支持Servlet规范

虽然netty可以充当http服务器,但是更多的人更倾向于使用tomcat,因为netty本身没有提供任何关于servlet规范的支持,netty的重心一直放在更底层,所以如果要使用netty实现http服务器的功能,需要自己根据需求开发

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值