NIO 初體驗遇到的坑記錄一下

服務端代碼:

坑: 因爲寫事件在selector中會一直會true, 所以會一直向client寫東西,所以要在寫事件完成後,取消寫事件。

package com.nio.yubo;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;
public class NioServer {
    
    public NioServer(int port) {
        this.port = port;
    }
    
    private int port;
    private Selector selector;    
    private ServerSocketChannel serverCh;
     
    private Selector getSelector() throws IOException
    {
        selector = Selector.open();
        serverCh = ServerSocketChannel.open();
        serverCh.configureBlocking(false);
        
        ServerSocket socket = serverCh.socket();
        InetSocketAddress address = new InetSocketAddress(port);
        socket.bind(address);
        
        serverCh.register(selector, SelectionKey.OP_ACCEPT);
        
        return selector;
    }
    
    public void listen()
    {
        System.out.println("Start to listen on port:" + this.port);
        while(true) 
        {
            try {
                selector.select();
                Set<SelectionKey> keys = selector.selectedKeys();
                Iterator<SelectionKey> it = keys.iterator();

                while(it.hasNext()) {
                    SelectionKey key = it.next();
                    it.remove();
                    
                    process(key);
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
        }
    }
    
    public  void process(SelectionKey key) {
        if(key.isAcceptable())
        {
            ServerSocketChannel server = (ServerSocketChannel) key.channel();
            SocketChannel channel = null;
            try {
                channel = server.accept();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            try {
                channel.configureBlocking(false);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            try {
                channel.register(selector, SelectionKey.OP_READ);
            } catch (ClosedChannelException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        else if(key.isReadable()) {
            //fix me
            SocketChannel channel = (SocketChannel)key.channel();
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            try {
                int len = channel.read(buffer);
                if(len > 0) {
                    buffer.flip();
                    System.out.println("Content len is:" + len + "pos is: " + buffer.position() + "limit:" + buffer.limit() + "ca:" +buffer.capacity());
                    String content = new String(buffer.array());
                    System.out.println("Content in readable is:" + content);                    
                    SelectionKey skey = channel.register(selector, SelectionKey.OP_WRITE);
                    skey.attach(content); // 爲一下次寫事件的key 準備數據
                }
                else
                {
                    channel.close();
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
            buffer.clear();            
            
        }
        else if (key.isWritable()) {
            SocketChannel channel = (SocketChannel)key.channel();
            String content = (String)key.attachment();
            ByteBuffer block = ByteBuffer.wrap( ("hello:" + content ).getBytes());
            try {
                channel.write(block);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            finally
            {
                key.cancel(); //  這裏是取消寫事件
            }
        }
    }
    
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        NioServer myServer = new NioServer(9999);
        try {
            myServer.getSelector();
            myServer.listen();
            
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }

}
 

客戶端代碼:

坑:

在把內容寫到buffer 後,在發送到channel 前,要把buffer flip() 一下,不然position, limit的值會不對,發到server的東西是空的。

package com.nio.yubo;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;

public class NioClient {

    Selector selector = null;
    SocketChannel channel = null;
    
    public void connect()
    {
        try {
            channel = (SocketChannel)SocketChannel.open();
            channel.connect(new InetSocketAddress( "127.0.0.1", 9999));
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            buffer.put("my name is tom".getBytes());
            buffer.flip(); // 這裏一定要記得恢復positon到0
            if(buffer.hasRemaining())
            {
                System.out.println("Client send: " + new String(buffer.array()));
                channel.write(buffer);
            }
            buffer.clear();
            
            channel.read(buffer);
            
            buffer.flip();
            if(buffer.hasRemaining())
            {
                System.out.println(new String(buffer.array()));
            }
            
            buffer.clear();
            channel.close();
            
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
    
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        new NioClient().connect();
    }

}
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章