netty 远程主机强迫关闭了一个现有的连接_手写一个简单的Netty服务器

他 大本文主要讲一下Netty服务器的工作原理以及编写方式。

Netty是一种NIO(同步非阻塞)形式的服务器,这种方式有什么好处呢?

最大的好处莫过于NIO是零拷贝的,也就是说数据可以直接从IO读至应用程序所开辟的内存中,因此Netty可以用于开发高性能的服务端。

NIO与其他形式IO的对比:

需要理解 同步,异步,阻塞,非阻塞的概念

cf12c1f3f2d6e6a913679fa4ba1837cd.png

f80ce617723714e76bd6bf4c4cfdeb63.png

同步和异步是针对通讯方式,而阻塞非阻塞是针对线程的等待状态。

BIO:Block IO,同步阻塞,不发处理效率比较低,线程之间通信耗时也比较久,比较依赖网速和带宽。

13620b334b8c67e230512cc35c935b6b.png

NIO:Non-Block IO, 同步非阻塞

28a47b61cc6699da09641cd1fa56d350.png

了解完这些之后,开始试图理解Netty的原理。

在使用NIO时,它的类库比较复杂,需要具备较为深厚的多线程编程功底,对新手不用好,而且原生NIO中存在bug,而且在客户端会产生断线重连,网络不稳定的问题。

所以采用Netty,原因在于其API简单。

Netty有三种线程模型:

(1)单线程模型

748f58bb1dd512674acec94c5fb2faa3.png

(2)多线程模型(并发量更高)

dda69e463b48852a1db403632e7ba786.png

(3)主从线程模型:

3e0bbc07d45e58a2df343660de38b9f8.png

第三种是最常见的,具体操作步骤如下:

(1)构建一对主从线程组

(2)定义服务器的启动类

(3)为服务器设置Channel

(4)设置处理从线程池的助手类初始化器

(5)监听启动和关闭服务器

在IDEA中开始书写:

新建Maven项目,在mvn中央仓库中找Netty的pom文件(选择4.1.25版本),引入:

    <groupId>com.imooc</groupId>
    <artifactId>netty-server</artifactId>
    <version>1.0-SNAPSHOT</version>

新建NettyServer启动类:(定义服务器所需要的各个模块)

//功能: 实现客户端发送一个请求,服务器会返回hello netty
public class HelloServer {

    public static void main(String[] args) throws InterruptedException {

        // 定义一对线程组
        //主线程组 利用NIO的线程组new出来 用于接收客户端的连接,但是不做任何处理
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        //从线程组 让线程组去做相应的任务
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            //服务端的启动类
            ServerBootstrap serverBootstrap = new ServerBootstrap();

            //将bossGroup和workerGroup丢进来,在server中设置两个线程组
            //将channel的类型设置为NIO双向通道
            //设置从线程组的助手类处理器,用于处理workGroup
            serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new HelloServerInitializer());

            //启动server: server绑定端口号,sync方法设置为同步的方式,等待8088端口启动完毕
            ChannelFuture channelFuture = serverBootstrap.bind(8088).sync();

            //设置关闭对应的的监听 sync设置为同步的方式
            channelFuture.channel().closeFuture().sync();
        } finally {
            //用优雅的方式关闭线程组
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }
}

接着设置Channel的初始化器:

a1486d00743248cf4c6b814500730fb4.png
//功能:初始化器,channel注册之后,会执行里面相应的初始化方法(也就是将handler逐一添加)
//socketChannel适用于通信的channel类型
public class HelloServerInitializer extends ChannelInitializer<SocketChannel> {

    //添加handler
    @Override
    protected void initChannel(SocketChannel channel) throws Exception {
        // 通过SocketChannel需获取对应的管道
        ChannelPipeline pipeline = channel.pipeline();

        //将自定义的和netty所提供的handler都添加至pipeline中
        //HttpServerCodec是netty自己提供的助手类,可以理解为拦截器(第一个参数为可以自己命名的助手类名字)
        pipeline.addLast("HttpServerCodec", new HttpServerCodec());

        //添加自定义的助手类,返回"hello netty~"
        pipeline.addLast(":customHandler", new CustomHandler());

    }
}

自定义Handler助手类:

//功能:创建自定义助手类
//SimpleChannelInboundHandler: 对于请求来讲,其实相当于[入站,入境]
public class CustomHandler extends SimpleChannelInboundHandler<HttpObject> {

    //功能:从缓冲区中读数据 (ChannelHandlerContext为channel的上下文对象)
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {

        //获取channel
        Channel channel = ctx.channel();

        if(msg instanceof HttpRequest){
            //打印显示客户端远程的地址
            System.out.println(channel.remoteAddress());

            //定义发送内容消息(通过缓冲区) 将数据写到缓冲区
            ByteBuf content = Unpooled.copiedBuffer("Hello netty~", CharsetUtil.UTF_8);

            //构建一个HttpResponse 参数:(1)http版本号 (2)状态(例如200,404)(3)相应的内容
            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content);

            //功能:为响应增加数据类型和长度
            //返回textplain即可,因为是返回字符串
            //返回可读的长度
            response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain");
            response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());

            //把response写入缓冲区中并刷到客户端
            ctx.writeAndFlush(response);
        }


    }

启动后,在浏览器中访问localhost:8090,即可访问到hello Netty。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值