1. 程式人生 > >JAVA NIO Selector構建簡單伺服器

JAVA NIO Selector構建簡單伺服器

JAVA NIO Selector構建簡單伺服器

ServerSocketChannel + Selector

NIOServer.java

public class NIOServer implements Runnable{

    private int clientNum = 0;
    private int bufferSize = 12;

    @Override
    public
void run() { try { // 建立通道和選擇器 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); Selector selector = Selector.open(); InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 5500); serverSocketChannel.
socket().bind(inetSocketAddress); // 設定通道非阻塞 繫結選擇器 serverSocketChannel.configureBlocking(false); /* * ServerSocketChannel只有accept */ serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT).attach("server"); System.
out.println("Server started .... port:5500"); while(true) { int readyChannels = selector.select(); if(readyChannels == 0) continue; Set selectedKeys = selector.selectedKeys(); Iterator keyIterator = selectedKeys.iterator(); while(keyIterator.hasNext()) { SelectionKey key = (SelectionKey)keyIterator.next(); // 判斷是哪個事件 if(key.isAcceptable()) {// 客戶請求連線 System.out.println(key.attachment()+ " - 接受請求事件"); ++clientNum; // 獲取通道 接受連線, // 設定非阻塞模式(必須),同時需要註冊 讀寫資料的事件,這樣有訊息觸發時才能捕獲 SocketChannel socketChannel = ((ServerSocketChannel) key.channel()).accept(); socketChannel.configureBlocking(false); socketChannel.register(selector, SelectionKey.OP_READ).attach("accept"+clientNum); System.out.println(key.attachment() + " - 已連線"); } else if (key.isConnectable()) { System.out.println(key.attachment()+ " - 連線事件"); } else if (key.isReadable()) { System.out.println(key.attachment()+ " - 讀資料事件"); SocketChannel clientChannel=(SocketChannel)key.channel(); ByteBuffer receiveBuf = ByteBuffer.allocate(bufferSize); clientChannel.read(receiveBuf); System.out.println(key.attachment()+ " - 讀取資料:" + getString(receiveBuf)); } else if (key.isWritable()) { System.out.println(key.attachment()+ " - 寫資料事件"); SocketChannel clientChannel = (SocketChannel) key.channel(); ByteBuffer sendBuf = ByteBuffer.allocate(bufferSize); String sendText = "helloc"; sendBuf.put(sendText.getBytes()); sendBuf.flip(); //寫完資料後呼叫此方法 clientChannel.write(sendBuf); } keyIterator.remove(); } } } catch (Exception e) { e.printStackTrace(); } } public String getString(ByteBuffer buffer){ StringBuffer builder = new StringBuffer(""); try{ for(int i = 0; i<buffer.position();i++){ builder.append((char)buffer.get(i)); } return builder.toString(); }catch (Exception ex){ ex.printStackTrace(); return builder.toString(); } } }

SocketChannel

NIOClient.java

public class NIOClient implements Runnable {

    private String tag = "client";
    private ByteBuffer readBuffer;
    private ByteBuffer writeBuffer;
    private boolean isConnected = false;
    private int bufferSize = 12;

    public NIOClient(String tag){
        this.tag = tag;
        readBuffer = ByteBuffer.allocate(bufferSize);
        writeBuffer = ByteBuffer.allocate(bufferSize);
    }

    @Override
    public void run() {

        try {

            Selector selector = Selector.open();

            SocketChannel socketChannel  = SocketChannel.open();

            socketChannel.configureBlocking(false);
            socketChannel.connect(new InetSocketAddress("127.0.0.1", 5500));
            socketChannel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_READ|SelectionKey.OP_WRITE).attach(tag);

            System.out.println(tag+" connect .... port:5500");

            while(true) {
                int readyChannels = selector.select();
                if(readyChannels == 0) continue;
                Set selectedKeys = selector.selectedKeys();
                Iterator keyIterator = selectedKeys.iterator();
                while(keyIterator.hasNext()) {

                    SelectionKey key = (SelectionKey)keyIterator.next();
                    // 判斷是哪個事件
                    if(key.isAcceptable()) {// 客戶請求連線
                        System.out.println(key.attachment()+ "is accepted by server");

                    } else if (key.isConnectable()) {
                        System.out.println(key.attachment()+ " connect ");
                        SocketChannel channel = (SocketChannel) key.channel();
                        if (channel.isConnectionPending()) {
                            try {
                                /*
                                 * 人為將程式中止,等待連線建立完成,否則會報如下錯誤
                                 * java.nio.channels.NotYetConnectedException at sun.nio.ch.SocketChannelImpl.ensureWriteOpen(SocketChannelImpl.java:274)
                                 */
                                if (channel.finishConnect()) {
                                    System.out.println(key.attachment()+" connect server succ");
                                    isConnected = true;
                                }
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    } else if (key.isReadable()) {
                        System.out.println(key.attachment()+ " read ");

                        SocketChannel clientChannel = (SocketChannel) key.channel();

                        try {
                            int len = clientChannel.read(readBuffer);
                            if (len == -1) {
                                System.out.println(key.attachment()+" read : len=-1");
                                // 說明連線已經斷開
                                selector.close();
                                socketChannel.close();
                            } else {
                                readBuffer.flip();
                                byte[] buffer = new byte[len];
                                readBuffer.get(buffer);
                                readBuffer.clear();
                                System.out.println(key.attachment()+" read : len=" + len + ", str=" + new String(buffer));
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }

                    } else if (key.isWritable()) {
                        System.out.println(key.attachment()+ " write ");
                        SocketChannel clientChannel = (SocketChannel) key.channel();
                        String str = "hellos";
                        byte[] buffer = str.getBytes();
                        writeBuffer.put(buffer);
                        writeBuffer.flip();
                        try {
                            System.out.println(key.attachment()+ " write : len=" + buffer.length + ", str=" + str);
                            clientChannel.write(writeBuffer);

                            try {
                                Thread.sleep(100);
                            }catch (Exception e){
                                e.printStackTrace();
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        writeBuffer.clear();
                    }
                    keyIterator.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

UnitTest

    @Test
    public void server(){
        Thread server = new Thread(new NIOServer());
        server.start();

        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Thread client1 = new Thread(new NIOClient("client1"));
        client1.start();

        Thread client2 = new Thread(new NIOClient("client2"));
        client2.start();

        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        client1.stop();
        client2.stop();

        server.stop();
	}

結果

執行結果