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

}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值