天天看點

非阻塞IO:NIO 服務端與用戶端 基于Socket的執行個體

BIO:Non-Block Input Output 非阻塞式的輸入和輸出,面向緩沖區的。示例代碼如下:

1、服務端Server

package com.example.nio.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class NioServer {
    private static int port = 8080;
    private static Selector selector;
    private static ByteBuffer buffer = ByteBuffer.allocate(1024);

    static{
        try {
            //擷取channel通道
            ServerSocketChannel server = ServerSocketChannel.open();
            //設定為非阻塞
            server.configureBlocking(false);
            //建立連接配接
            InetSocketAddress address = new InetSocketAddress(port);
            server.bind(address);
            //擷取選擇器,用于輪詢
            selector = Selector.open();
            //使用給定的選擇器注冊此通道
            server.register(selector, SelectionKey.OP_ACCEPT);
            System.out.println("BioServer 已經啟動,監聽端口是:"+port);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void start (){
        try {
            //開始進行輪詢
            while(true){
                //檢查其相應的通道有沒有已準備好進行I/O
                int count =  selector.select();
                if(count == 0){
                    continue;
                }
                //擷取輪詢的key,并逐個對其進行處理
                Set<SelectionKey>  keys = selector.selectedKeys();
                Iterator<SelectionKey> i = keys.iterator();
                while(i.hasNext()){
                    SelectionKey key = i.next();
                    //對每一個key進行處理
                    process(key);
                    i.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void process(SelectionKey key) throws IOException {
        //讀寫資料
        if(key.isAcceptable()){
            ServerSocketChannel setver = (ServerSocketChannel)key.channel();
            SocketChannel client = setver.accept();
            client.configureBlocking(false);
            client.register(this.selector,SelectionKey.OP_READ);
        }else if(key.isReadable()){
            SocketChannel client = (SocketChannel)key.channel();
            int len = client.read(this.buffer);
            if(len > 0){
                buffer.flip();
                String message = new String(buffer.array(),0,len);
                client.register(selector,SelectionKey.OP_WRITE, message);
            }
            buffer.clear();
        }else if(key.isWritable()){
            SocketChannel client = (SocketChannel)key.channel();
            String message = (String)key.attachment();
            System.out.println("服務端接收到的資訊為:"+ message);
            client.write(ByteBuffer.wrap(("Clint Say:"+ message).getBytes()));
            client.close();
        }
    }

    public static void main(String[] args) {
        //NIO代碼
        new NioServer().start();
    }
}
           

2、用戶端Client

package com.example.nio.client;

import java.io.*;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;

public class NioClient {
    private static Selector selector;
    private static SocketChannel socketChannel;
    static {
        try {
            //擷取channel通道
            socketChannel = SocketChannel.open();
            //設定為非阻塞
            socketChannel.configureBlocking(false);
            //建立連接配接
            socketChannel.connect(new InetSocketAddress("localhost",8080));
            //擷取選擇器,用于輪詢
            selector = Selector.open();
            //使用給定的選擇器注冊此通道
            socketChannel.register(selector, SelectionKey.OP_READ);
            while (!socketChannel.finishConnect()){
                System.out.println("重新連接配接......");
            }
            System.out.println("用戶端已連接配接到服務端......");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        //NIO
        try {
            //設定緩沖區
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            new clientThread(selector, socketChannel).start();
            while(true){
                System.out.println("send:");
                Scanner scanner = new Scanner(System.in);
                String name = scanner.nextLine();
                buffer.put(name.getBytes());
                buffer.flip();
                socketChannel.write(buffer);
                buffer.clear();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    static class clientThread extends Thread{
        private Selector selector;
        private SocketChannel socketChannel;

        public clientThread(Selector selector, SocketChannel socketChannel) {
            this.selector = selector;
            this.socketChannel = socketChannel;
        }

        public void run(){
            try {
                //讀寫資料
                while (true){
                    int count = selector.select();
                    if(count == 0){
                        continue;
                    }
                    //擷取輪詢的key,并逐個對其進行處理
                    Set<SelectionKey> keys = selector.selectedKeys();
                    Iterator<SelectionKey> i = keys.iterator();
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    while(i.hasNext()){
                        SelectionKey key = i.next();
                        if(key.isValid()){
                            if(key.isReadable()){
                                SocketChannel socketChannel = (SocketChannel)key.channel();
                                socketChannel.read(byteBuffer);
                                byteBuffer.flip();
                                byte[] bytes = new byte[byteBuffer.remaining()];
                                byteBuffer.get(bytes);
                                System.out.println("讀取到的資訊為:"+ new String(bytes));
                                byteBuffer.clear();
                            }
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
           

最後給出運作結果截圖,這個示例稍微有點bug,有興趣的可以研究下怎麼解決:

非阻塞IO:NIO 服務端與用戶端 基于Socket的執行個體
非阻塞IO:NIO 服務端與用戶端 基于Socket的執行個體

繼續閱讀