NIO非同期および同期ブロッキングブロッキング---網状に遷移(非同期イベント駆動型ネットワークアプリケーションフレームワーク)

BIO与NIO

IOは、同期ブロッキング形で、NIO同期、非同期NIOはJDK1.7後、アップグレードパッケージNIOライブラリを具体化しなかった非ブロックの形は、非同期の非ブロッキングをサポート
モデルNIO2.0(AIO)の学生を
同期ブロッキングIO、サーバーの実装:BIOクライアントは、接続がスレッドの不要なオーバーヘッドを引き起こす何もしない場合、接続要求は、処理のためのスレッドを開始する必要がありますサーバーを持っていることを接続するスレッドのモデルは、当然のことながら、スレッドプールのメカニズムによって改善することができます。
NIO:非ブロッキングIO同期は、サーバ、すなわち、クライアントによって送信された接続要求がマルチプレクサに登録されているスレッドの実現のモードを要求し、マルチプレクサはポーリングI / Oリクエストに接続されています。処理のためのスレッドを開始します。
AIO(NIO.2は):IO非同期ノンブロッキング、サーバーがスレッドを達成するために有効な要求モードである、クライアントのI / O要求は、アプリケーションプロセスのスレッドを開始し、その後、通知サーバにOSによって完成しています。

同期は、アプリケーションが直接読み取りおよび書き込み操作のIOに関与することになりますし、私たちのアプリケーションは、データの準備ができるまでは、特定の方法に直接ブロックします:
データを取得する準備ができている場合、またはリアルタイム検査データに回転戦略の準備状態を使用します。
非同期は、私たちが読んで運転する場合、IO関係を記述するためのプログラムを必要としない、すべてのIOは、読み取りおよび書き込み操作は、オペレーティング・システムに、直接我々のアプリケーションに関連していない
IO読み取りおよび書き込み操作は、我々はアプリケーションを送信する際に、システムが終了します通知は、我々のアプリケーションは直接データポールを取ることができます。

擬似非同期

BIOは、クライアントは、ハンドルにスレッドを必要とするので、我々は、複数のクライアントへのハンドルを要求するアクセスするスレッドプールの後端の使用を最適化し、Mの数は、クライアント側構成:Nスレッドプールのスレッドの最大数との比率を、前記Mは、スレッドの大規模な枯渇をもたらす同時アクセスを防止するために、柔軟なスレッドの最大値を設定することができるスレッドプールスレッドのリソース割り当てによって、Nよりもはるかに大きくてもよいです。
原理:
クライアントへの新しいアクセス、クライアントのソケットタスク(ジャワ、Runnableインタフェースを実装するタスクのタスク)にパッケージスレッドプールの後端に配信スレッドプールのサイズは、メッセージキューに設けることができるので、処理され最大スレッドプール、その足跡は、多くのクライアントの同時アクセス、またはダウンタイムは資源の枯渇につながることはありませんどんなに、制御可能ではありませんので。

IOモデルの関係

ここに画像を挿入説明

ブロッキングは何ですか

概念をブロッキング:ネットワークデータへのアプリケーションのアクセスを、伝送ネットワークが遅い場合は、プログラムは直接送信に、待っているが完了する。

ノンブロッキングとは何ですか

アプリケーションが待つことなく、すぐデータに直接アクセスすることができます。
IOは、同期ブロッキングフォーム、NIOの非ブロッキング同期形です。NIOは、JDK1.7後、非同期実装NIOライブラリパッケージをアップグレードしない
、非同期通信モデル閉塞料NIO2.0をサポートしています(AIO)

SELECTキー

。1、SelectionKey.OP_CONNECT
2、SelectionKey.OP_ACCEPT
。3、SelectionKey.OP_READ
。4、SelectionKey.OP_WRITE
あなたが複数のイベントに興味を持っている場合、あなたが"ビットまたは"接続する定数演算子を使用することができるが、以下のように:
INT = interestSetとSelectionKey .OP_READ | SelectionKey.OP_WRITE、
ソースとSelectionKeyクラスで、私たちは次の4つの属性を参照することができ、4つの変数は、イベントの4種類を表すために使用される:読み込み、書き込みを、接続することができ、許容可能な接続

ノンブロッキング:

########クライアント


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();
		}

#######サーバー

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();
				}
			}
}

なぜネッティー

開発用のJDK NIOライブラリの理由とその開発者の作業をお勧めしない理由は、この節では、要約します:

  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相关的问题单如下:
    

ここに画像を挿入説明

ネッティーシナリオ

オープン・ソース・フレームワークに分布ダボ1は、飼育係、RocketMQが使用RPC通信の基礎となることは網状です。
2.ゲーム開発、基本的な使用ネッティー通信。

シングルクライアント接続:

サーバー:

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();
        }

    }
扱う:
      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クラスServerHandler2はChannelInboundHandlerAdapter {延び
@Override
公共ボイドchannelRead(ChannelHandlerContext CTX、オブジェクトMSG)は例外{スロー
super.channelRead(CTX、MSG)を、
System.out.println( "服务端2消息" + MSG)。
ctx.channel()writeAndFlush(「これはServerHandler2ある」+のSystem.currentTimeMillis())。
}
}

クライアント

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();
    }
}

}
ハンドル:

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

}

公開された26元の記事 ウォンの賞賛0 ビュー696

おすすめ

転載: blog.csdn.net/YHM_MM/article/details/104006727