NIO asynchronous and synchronous blocking blocking --- transition to netty (an asynchronous event-driven network application framework)

BIO given NIO

IO is a synchronous blocking form, the form of non-blocking NIO synchronous, asynchronous NIO did not materialize, the upgrade package NIO library after JDK1.7, supports asynchronous non-blocking
students model NIO2.0 (AIO)
BIO: synchronous blocking IO, server implementation a model for a connecting thread that the client has the server when the connection request will need to start a thread for processing, if the connection does not do anything to cause unnecessary overhead of thread, of course, can be improved by a thread pool mechanism.
NIO: the IO synchronous non-blocking, the server requests a mode of realization of a thread, i.e., the connection request sent by the client are registered to the multiplexer, the multiplexer is connected to the polling I / O request when start a thread for processing.
AIO (NIO.2): the IO asynchronous non-blocking, the server is a valid request mode to achieve a thread, the client I / O requests are completed by the OS to the notification server and then to start the application process threads.

Synchronization, the application will be directly involved in the IO read and write operations, and our application will block directly to a particular method, until the data is ready:
or to use a ready state in rotation strategy in real time inspection data, if it is ready to get data.
asynchronous, all the IO read and write operations to the operating system, not directly related to our application, we do not need a program to read and write IO relations, when the operating
system is finished when the IO read and write operations, we will send the application notice, our application can directly take data pole.

Pseudo-asynchronous

Since BIO a client needs a thread to handle, we optimize the use of the rear end of the thread pool to handle requests access to a plurality of clients, the number of M form the client side: the ratio between the maximum number of threads N of the thread pool, wherein M may be much greater than N, by a thread pool thread resource allocation can flexibly set the maximum value of the thread, to prevent concurrent access leading to massive depletion of the thread.
Principle:
when a new access to the client, the client's Socket packaged into a Task (Task task which implements the java Runnable interface) delivered to the rear end of the thread pool is processed, since the size of the thread pool may be provided in the message queue and the maximum thread pool, so its footprint is controllable, no matter how many clients concurrent access, or downtime will not lead to the depletion of resources.

IO model relationships

Here Insert Picture Description

What is blocking

Blocking concepts: applications access to network data, the transmission if the network is slow, then the program has been waiting for, directly to the transmission is completed.

What is non-blocking

An application can have direct access to ready data, without having to wait.
IO is a synchronous blocking form, NIO non-blocking synchronous form. NIO does not implement asynchronous, after JDK1.7, upgrade the NIO library package
, supports asynchronous communication model obstruction charges NIO2.0 (AIO)

Select KEY

. 1, SelectionKey.OP_CONNECT
2, SelectionKey.OP_ACCEPT
. 3, SelectionKey.OP_READ
. 4, SelectionKey.OP_WRITE
if you are interested in more than one event, you can use "bit or" constant operator to connect, as follows:
int = interestSet the SelectionKey .OP_READ | SelectionKey.OP_WRITE;
in the source SelectionKey class we can see the following four attributes, four variables used to represent four different types of events: read, write, can be connected, connected acceptable

Examples

Non-blocking:

######## Client


public static void main(String[] args) throws IOException {
			System.out.println("客户端已经被启动:");
			//创建socket通道
			SocketChannel socketChannel=SocketChannel.open(new InetSocketAddress("127.0.0.1",8080));
			//切换异步非阻塞
			socketChannel.configureBlocking(false);
			//指定缓存区大小
			ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
			byteBuffer.put(new Date().toString().getBytes());
			//切换到读取模式
			byteBuffer.flip();
			socketChannel.write(byteBuffer);
			byteBuffer.clear();
			socketChannel.close();
		}

####### Server

public static void main(String[] ages) throws IOException {
	System.out.println("服务端启动..........");
	//创建服务通道
			ServerSocketChannel open = ServerSocketChannel.open();
			//异步非阻塞
			open.configureBlocking(false);
			//绑定连接
			open.bind(new InetSocketAddress(8080));
			//获取选择器
			Selector selector = Selector.open();
			//将通道注册到选择器中
			open.register(selector, SelectionKey.OP_ACCEPT);
			while(selector.select()>0) {
				//获取当前选择器,有注册已经监听到的事件
				Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
				//判断事件准备就绪
				while(iterator.hasNext()) {
					//获取准备接续事件
					SelectionKey next = iterator.next();
					//判断事件是否就绪(没有就绪的)
					if(next.isAcceptable()) {
						//获取客户端的连接
						SocketChannel accept = open.accept();
						//设置阻塞事件
						accept.configureBlocking(false);
						//将该通道注册到选择器上
						accept.register(selector, SelectionKey.OP_READ);
					}else if(next.isReadable()) {//就绪的
						//获取当前状态的通道
						SocketChannel channel = (SocketChannel) next.channel();
						//读取数据
						int len=0;
						ByteBuffer allocate = ByteBuffer.allocate(1024);
						while((len=(channel.read(allocate)))>0) {
							allocate.flip();
							System.out.println(new String(allocate.array(),0,len));
							allocate.clear();
						}
						
					}
					iterator.remove();
				}
			}
}

Why netty

In this section, we summarize why not recommend that developers work with the JDK NIO libraries Reasons for development:

  1.  NIO的类库和API繁杂,使用麻烦,你需要熟练掌握Selector、ServerSocketChannel、SocketChannel、ByteBuffer等;
    
  2.  需要具备其它的额外技能做铺垫,例如熟悉Java多线程编程,因为NIO编程涉及到Reactor模式,你必须对多线程和网路编程非常熟悉,才能编写出高质量的NIO程序;
    
  3.  可靠性能力补齐,工作量和难度都非常大。例如客户端面临断连重连、网络闪断、半包读写、失败缓存、网络拥塞和异常码流的处理等等,NIO编程的特点是功能开发相对容易,但是可靠性能力补齐工作量和难度都非常大;
    
  4.  JDK NIO的BUG,例如臭名昭著的epoll bug,它会导致Selector空轮询,最终导致CPU 100%。官方声称在JDK1.6版本的update18修复了该问题,但是直到JDK1.7版本该问题仍旧存在,只不过该bug发生概率降低了一些而已,它并没有被根本解决。该BUG以及与该BUG相关的问题单如下:
    

Here Insert Picture Description

Netty scenarios

Dubbo 1. distributed in open source framework, Zookeeper, RocketMQ underlying rpc communication using is netty.
2. The game development, the underlying use netty communications.

Single-client connection:

Server:

public static void main(String[] args) {
        startServer();
    }

    public static void startServer(){
        //1.定义server启动类
        ServerBootstrap serverBootstrap = new ServerBootstrap();

        //2.定义工作组:boss分发请求给各个worker:boss负责监听端口请求,worker负责处理请求(读写)
        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup worker = new NioEventLoopGroup();

        //3.定义工作组
        serverBootstrap.group(boss,worker);

        //4.设置通道channel
        serverBootstrap.channel(NioServerSocketChannel.class);//A
        //serverBootstrap.channelFactory(new ReflectiveChannelFactory(NioServerSocketChannel.class));//旧版本的写法,但是此过程在A中有同样过程

        //5.添加handler,管道中的处理器,通过ChannelInitializer来构造
      serverBootstrap.childHandler(new ChannelInitializer<Channel>() {
            @Override
            protected void initChannel(Channel channel) throws Exception {
                //此方法每次客户端连接都会调用,是为通道初始化的方法

                //获得通道channel中的管道链(执行链、handler链)
                ChannelPipeline pipeline = channel.pipeline();
                pipeline.addLast(new StringDecoder());
                pipeline.addLast("serverHandler1",new ServerHandler());
                pipeline.addLast("serverHandler2",new ServerHandler2());
                pipeline.addLast(new StringEncoder());

                System.out.println("success to initHandler!");
            }
        });

        //6.设置参数
        //设置参数,TCP参数
        serverBootstrap.option(ChannelOption.SO_BACKLOG, 2048);         //连接缓冲池的大小
        serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);//维持链接的活跃,清除死链接
        serverBootstrap.childOption(ChannelOption.TCP_NODELAY, true);//关闭延迟发送

        //7.绑定ip和port
        try {
            ChannelFuture channelFuture = serverBootstrap.bind("127.0.0.1", 8080).sync();//Future模式的channel对象
            //7.5.监听关闭
            channelFuture.channel().closeFuture().sync();  //等待服务关闭,关闭后应该释放资源
        } catch (InterruptedException e) {
            System.out.println("server start got exception!");
            e.printStackTrace();
        }finally {
            //8.优雅的关闭资源
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }

    }
handle:
      public class ServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
	super.channelRead(ctx, msg);
	System.out.println("服务端消息:"+msg.toString());
	ctx.channel().writeAndFlush("serverHandler"+System.currentTimeMillis());
	//把消息往下一个Handler传
    ctx.fireChannelRead(msg);
}

}
public class ServerHandler2 extends ChannelInboundHandlerAdapter{
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
super.channelRead(ctx, msg);
System.out.println("服务端2消息 "+msg);
ctx.channel().writeAndFlush(“this is ServerHandler2”+System.currentTimeMillis());
}
}

Client

public class NettySingleClient {
public static void main(String[] args) {
    startClient();
}

public static void startClient(){
    //1.定义服务类
    Bootstrap clientBootstap = new Bootstrap();

    //2.定义执行线程组
    EventLoopGroup worker = new NioEventLoopGroup();

    //3.设置线程池
    clientBootstap.group(worker);

    //4.设置通道
    clientBootstap.channel(NioSocketChannel.class);

    //5.添加Handler
    clientBootstap.handler(new ChannelInitializer<Channel>() {
        @Override
        protected void initChannel(Channel channel) throws Exception {
            System.out.println("客户端初始化:");
            ChannelPipeline pipeline = channel.pipeline();
            pipeline.addLast("StringDecoder",new StringDecoder());
            pipeline.addLast("StringEncoder",new StringEncoder());
            pipeline.addLast("ClientHandler",new ClientHandler());
        }
    });

    //6.建立连接
    ChannelFuture channelFuture = clientBootstap.connect("127.0.0.1",8080);
    try {
        //7.测试输入
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        while(true){
            System.out.println("请输入:");
            String msg = bufferedReader.readLine();
            channelFuture.channel().writeAndFlush(msg);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        //8.关闭连接
        worker.shutdownGracefully();
    }
}

}
handle:

public class ClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    System.out.println("client receive msg:"+msg.toString());
}

}

Published 26 original articles · won praise 0 · Views 696

Guess you like

Origin blog.csdn.net/YHM_MM/article/details/104006727