NIOサン作業2、のSocketChannel

続きBenpian https://blog.csdn.net/HouXinLin_CSDN/article/details/104263694後。

そのJavaのNIOのSocketChannelがネットワークTCPソケットチャネルに接続されており、ソケットなど、のSocketChannelは、一般的に次の方法を使用して作成することができ、クライアントの要求のために使用されますが、注意してください。
接続が成功した場合、接続呼び出して、ブロッキングSocketChannelへ、真、そうでない場合は障害物やスローを返します。
接続が成功した場合はすぐに非ブロックモードでは、それはすぐに完了しない場合、それは偽を返しますが、それはfalseを返した後、数秒以内に、それが正常に接続することが可能で、読み書きやエラーには、この時間が発生し、呼び出し後に必要、trueを返しますfinishConnect接続の完了を確実にするために、接続が成功したコールfinishConnect場合はtrueを返し、そうでない場合は接続しようと、IO例外がスローされ失敗してきました。

モードを切り替えるには、非ブロックモードに代わって呼び出し、入ってくる偽のconfigureBlocking行うことができます。

SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("127.0.0.1", 8000));

JavaのNIOのServerSocketChannelチャネルは、TCP接続が要求を聞くことができ、サーバであり、ServerSocketを同じ。

旧バージョンからのSocketChannelとのServerSocketChannel異なる、、、のServerSocketを受け入れるための呼び出しの古いバージョンが接続要求まで、およびNIOの非ブロックの下に、現在のスレッドをブロックしますと言うことですつまり、古いバージョンをブロックしている、とNIOは非ブロックすることができ要求を受け入れるようにコールがない場合は、すぐにクライアントに接続して取得する方法を、次に、ヌルを返しますか?答えはセレクタです。指定したイベントが発生したときにセレクタレジスタに指定されたイベントでは、セレクタは、対応する応答ロジックを作るためにこのイベントによれば、反応します。

ここでのイベントは、書き込み、読み込み、中とSelectionKeyで定義されているように、接続を以下の図が含まれ、接続イベントは、合意されました。
ここに画像を挿入説明

サンプルコード

最初はサービス側である、のServerSocketChannelを書くには、次の手順が必要です:
1.セレクタを作成します。
2.のServerSocketChannel、およびセット非ブロックモードを作成します。
登録したセレクタに興味のある3.イベント。
4.セレクタポーリング除去イベントが発生し、応答にします。

1,2,3-同期コード次のように

Selector selector =Selector.open();
ServerSocketChannel serverSocketChannel =ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(8000));
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);

メソッドのセレクタの選択数によって行われた次の世論調査では、ブロックのこの方法ことIO操作、ノートを用意してきました。そして、のSelectableChannelは、適切なロジックを作るかどうかのServerSocketChannelのSocketChannelが指定したイベントが発生したときに、オブジェクトが発生したイベントを判断することですどちらものSelectableChannelを継承し、セレクタでマークを登録表すとSelectionKey、selectedKeysですべてとSelectionKeyを取得します。

登録するのServerSocketChannel呼び出した後、それがあること、とSelectionKeyオブジェクトを返し、イベントが合意された接続オブジェクトで行われます、確認するために、serverSelectKey ==隣に判断サービスが受け入れるイベントその下で、それは本当等しくすることはありません。

 public static void main(String[] args) throws InterruptedException, IOException {
     Selector selector =Selector.open();
     ServerSocketChannel serverSocketChannel =ServerSocketChannel.open();
     serverSocketChannel.bind(new InetSocketAddress(8000));
     serverSocketChannel.configureBlocking(false);
	 SelectionKey serverSelectKey = serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
	  System.out.println("服务端启动成功");
     for(;;){
         int select = selector.select();
         Set<SelectionKey> selectionKeys = selector.selectedKeys();
         Iterator<SelectionKey> iterator = selectionKeys.iterator();
         while (iterator.hasNext()){
             SelectionKey next = iterator.next();
             iterator.remove();
             if (next.isAcceptable()){
                 System.out.println("isAcceptable=="+(next ==serverSelectKey));
                 acceptHandler(serverSocketChannel,selector);
             }
             if (next.isReadable()){
                 readHandler(next,selector);
             }
         }
     }
 }

別のイベントの場合、それはisXXXXとSelectionKeyオブジェクトによって判断することができます。

接続、acceptHandlerプロセスが呼び出されることが合意された場合。以下の通りです。が、また、セットのSocketChannel非ブロックモードに同意した後、セレクタを登録するには、書き込み操作は、入射SelectionKey.OP_READを監視するために登録するときに表示され、このクライアントを受信する準備ができている、とクライアントを出力します欢迎来到祖安

 private static void acceptHandler(ServerSocketChannel serverSocketChannel,Selector selector) throws IOException{
     SocketChannel accept = serverSocketChannel.accept();
     accept.configureBlocking(false);
     accept.register(selector,SelectionKey.OP_READ);
     accept.write(Charset.forName("utf-8").encode("欢迎来到祖安"));
 }

クライアントは、クライアントが-1にそれを読んだ後、接続を閉じるには、閉じreadHandler処理する方法、により、イベントを書いている、またはサーバがポーリングを空にします。場合

 private static  void readHandler(SelectionKey selectionKey) {
     try {
         SocketChannel channel = (SocketChannel)selectionKey.channel();
         ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
         String request="";
         int read = channel.read(byteBuffer);
         if (read==-1){
             channel.close();
             return;}
         while (read>0){
             byteBuffer.flip();
             request +=Charset.forName("utf-8").decode(byteBuffer);
             read=channel.read(byteBuffer);
         }
         System.out.println("客户端数据:"+request);
     }catch (IOException e){
     }
 }

クライアントのテストでは、サーバーに接続するための10個のスレッドを提出し、スレッドプールによって、6回の出力データ。

クライアントは、データを受信し、再びポーリング裁判官によって同じ登録イベントセレクタをお読みください。

public class Main5NIOClient implements Runnable {
    class ClientRecvMsg extends Thread {
        private Selector selector;
        public ClientRecvMsg(Selector selector) {
            selector = selector;
        }
        @Override
        public void run() {
            super.run();
            for (; ; ) {
                try {
                    selector.select();
                    Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                    while (iterator.hasNext()) {
                        SelectionKey next = iterator.next();
                        if (next.isReadable()) {
                            ByteBuffer buffer = ByteBuffer.allocate(1024);
                            ((SocketChannel) next.channel()).read(buffer);
                            buffer.flip();
                            System.out.println("服务端:" + Charset.forName("utf-8").decode(buffer));
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    @Override
    public void run() {
        SocketChannel socketChannel = null;
        try {
            //创建Selector
            Selector selector = Selector.open();
            //创建SocketChannel
            socketChannel = SocketChannel.open();
            //非阻塞模式
            socketChannel.configureBlocking(false);
            //连接,没有立即完成则返回false
            socketChannel.connect(new InetSocketAddress("127.0.0.1", 8000));
            if (socketChannel.finishConnect()) {
                socketChannel.register(selector,SelectionKey.OP_READ);
                new ClientRecvMsg(selector).start();
                for (int i = 0; i < 6; i++) {
                    String info = "我是祖安" + i + "号";
                    socketChannel.write(Charset.forName("utf-8").encode(info));
                    TimeUnit.SECONDS.sleep(1);
                }
            }
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            try {
                if (socketChannel != null) {
                    socketChannel.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            executorService.execute(new Main5NIOClient());
        }
    }
}

シングルスレッドのサーバを実行した後に簡単に複数の同時要求を処理します。

間違っている場合は、多くのことを指摘してください

公開された42元の記事 ウォン称賛7 ビュー7745

おすすめ

転載: blog.csdn.net/HouXinLin_CSDN/article/details/104274688