Netty 初识

作者: Always_July | 来源:发表于2021-04-01 11:54 被阅读0次

Netty 是什么

Netty is a NIO client server framework which enables quick and easy development of network applications such as protocol servers and clients. It greatly simplifies and streamlines network programming such as TCP and UDP socket server.

'Quick and easy' doesn't mean that a resulting application will suffer from a maintainability or a performance issue. Netty has been designed carefully with the experiences earned from the implementation of a lot of protocols such as FTP, SMTP, HTTP, and various binary and text-based legacy protocols. As a result, Netty has succeeded to find a way to achieve ease of development, performance, stability, and flexibility without a compromise.

官网介绍是:
Netty是一个NIO客户端服务器框架,可以快速、轻松地开发网络应用程序,如协议服务器和客户端。它极大地简化和简化了网络编程,如TCP和UDP套接字服务器。

介绍中提到了NIO这个关键字,英文全称是Non blocking IO,非阻塞IO。学习过Java Socket编程的人应该会了解到阻塞IO。

Linux 网络I/O 模型简介

阻塞I/O

image.png

非阻塞I/O

image.png

轮询检查状态

I/O 复用

Linux 提供select/poll,进程将一个或多个fd传递给select或poll系统调用,阻塞在select操作上,这样select/poll 可以帮我们侦测多个fd是否处于就绪状态。select/poll是顺序扫描fd是否就绪,而且支持的fd数量有限,因此它的使用受到了一些制约。Linux提供了一个epoll系统调用,epoll使用基于事件驱动方式代替顺序扫描,因此性能更高。当有fd就绪时,立即回调函数rollback。

image.png
select/poll 缺点
  1. 每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大。
  2. 每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大。
  3. select支持的文件描述符数量太少了,默认是1024。
epoll
  1. 内核与用户空间共享一块内存。
  2. 通过回调解决遍历问题。
  3. fd没有限制,可以支撑10万连接。

信号驱动 I/O

首先开启套接口信号驱动I/O功能,并通过系统调用sigaction执行一个信号处理函数(此系统调用立即返回,进程继续工作,它是非阻塞的)。当数据准备就绪时,就为该进程生成一个SIGIO信号,通过信号回调通知应用程序调用recvfrom来读取数据,并通知主函数处理数据。


image.png

异步I/O

告知内核启动某个操作,并让内核再整个操作完成后(包含将数据从内核复制到用户自己的缓冲区)通知我们。这种模型与信号驱动模型的主要区别是:信号驱动I/O由内核通知我们何时可以开始一个I/O操作;异步I/O通知我们I/O操作何时已完成。


image.png

Netty 的优势

quick and easy

Design

  • Unified API for various transport types-blocking and non-blocking socket
  • Flexible to use
  • Simple but powerful thread-model
  • True connectionless datagram socket support
  • Chaining of logics to make reuse easy

Easy to Use

  • Well-documented Javadoc and plenty of examples provided
  • No additional dependencies except JDK 1.6 (or above). Some features are supported only in Java 1.7 and above. Other features may have other dependencies, but these are optional

Perfermance

  • Better throughput; lower latency than core Java APIs
  • Less resource consumption because of pooling and reuse
  • Minimized unnecessary memory copy

Robobustness

  • No more OutOfMemoryError due to fast, slow, or overloaded connection.
  • No more unfair read/write ratio often found in a NIO application in high-speed

Security

  • Complete SSL/TSL And Start TLS support
  • Runs in a restricted environment such as Applet or OSGI

Community

  • Release early,release often
  • Active

Netty Demo

maven dependency

    <dependencies>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.32.Final</version>
        </dependency>
    </dependencies>

Server

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

import java.net.InetSocketAddress;


public class EchoServer {
    private final int port;

    public EchoServer(int port) {
        this.port = port;
    }
    public void start() throws InterruptedException {
        EventLoopGroup group = new NioEventLoopGroup();
        try{
            ServerBootstrap b = new ServerBootstrap();
            b.group(group)
                    .channel(NioServerSocketChannel.class)
                    .localAddress(new InetSocketAddress(port))
                    // when a connection is accepted,which create a child channel.
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch){
                            // channelPipeline hold all off the different  ChannelHandlers
                            ch.pipeline().addLast(new EchoServerHandler());
                        }
                    });
            ChannelFuture f = b.bind().sync();
            System.out.println(EchoServer.class.getName() +" started and listen on " + f.channel().localAddress());
            // sync() method will cause this to block until the server is bound
            f.channel().closeFuture().sync();
        }catch(Exception e){
            e.getMessage();
        }finally {
            group.shutdownGracefully().sync();
        }
    }

    public static void main(String[] args) throws Exception {
        new EchoServer(9999).start();
    }
}

EchoServerHandler

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;

public class EchoServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ByteBuf in = (ByteBuf) msg;
        System.out.println("Server received: " + in.toString(CharsetUtil.UTF_8));
        ctx.write(in);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx)  {
        //  Flush all previous written messages (that are pending) to the remote peer, and close the channel after the operation is complete.
        ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
                .addListener(ChannelFutureListener.CLOSE);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)  {
        cause.printStackTrace();
        ctx.close();
    }
}

Client


import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.net.InetSocketAddress;


public class EchoClient {
    private final String host;
    private final int port;

    public EchoClient(String host, int port) {
        this.host = host;
        this.port = port;
    }

    public void start() throws InterruptedException {
        EventLoopGroup group = new NioEventLoopGroup();
        try{
            Bootstrap bootstrap = new Bootstrap();

            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .remoteAddress(new InetSocketAddress(host,port))
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch){
                            ch.pipeline().addLast(new EchoClientHandler());
                        }
                    });
            ChannelFuture f = bootstrap.connect().sync();
            f.channel().closeFuture().sync();
        }catch(Exception e){
            e.getMessage();
        }finally {
            group.shutdownGracefully().sync();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        EchoClient echoClient = new EchoClient("127.0.0.1",9999);
        echoClient.start();
    }
}

EchoClientHandler

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;


public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        // must Flush
        ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8));
    }

    @Override
    public void channelRead0(ChannelHandlerContext ctx,
                             ByteBuf in) {
       System.out.println("Client received: " + ByteBufUtil
                .hexDump(in.readBytes(in.readableBytes())));
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx,
                                Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

Server console

com.daxiyan.study.netty.chapter2.EchoServer started and listen on /0:0:0:0:0:0:0:0:9999
Server received: Netty rocks!

Client console

Client received: 4e6574747920726f636b7321

参考文档及书籍

Netty_ Home
Netty权威指南(第2版)
Netty In Action

相关文章

  • Netty:初识Netty

    前文总结了NIO的内容,有了NIO的一些基础之后,我们就可以来看下Netty。Netty是Java领域的高性能网络...

  • 初识Netty

  • Netty初识

    话不多说直接从代码入手 服务器端 以上是用netty实现最简单的服务器程序的一段代码,相比于用NIO实现相应功能,...

  • Netty 初识

    Netty 是什么 Netty is a NIO client server framework which en...

  • 初识Netty

    《Netty 实战》 前言 之前有个这样的一个bug,服务A的接口1依赖服务B的接口2,由于服务B接口2耗时升高,...

  • Netty挖掘机(三)结合Spring搭建Netty脚手架

    上文《Netty挖掘机(二)初识Netty》,主要介绍了Netty的特性及其如何启动,启动的相关配置说明。这一篇主...

  • netty系列(一) 初识netty

    背景 对公司http服务进行压力测试,选择netty+springmvc与传统的tomcat服务进行对比。选择的业...

  • (一)初识Netty

    一、认识Netty之前 二、Netty是什么 三、Netty的使用场景

  • netty(八)初识Netty-channel

    一、channel 1.1 channel的主要方法 1)close() 可以用来关闭 channel2)clos...

  • 【初识Netty】IO模型

    Netty是什么? 作为Java开发者,相信大家或多或少都听说过或者是使用过Netty,而说起Netty,就不得不...

网友评论

    本文标题:Netty 初识

    本文链接:https://www.haomeiwen.com/subject/ovhtkltx.html