java nio selector

package com.selector;

import org.junit.Test;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

/**
 * Created by wang on 15-3-26.
 */
public class SelectorSocket {

    private  int PORT = 8888;
    private ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

    @Test
    public void selectSocket() throws IOException, InterruptedException {
        System.out.println("listening on port "+PORT);
        ServerSocketChannel  serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);

        ServerSocket serverSocket = serverSocketChannel.socket();
        serverSocket.bind(new InetSocketAddress(PORT));

        Selector selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true){
            int n = selector.select();
            if (n == 0){
                continue;
            }

            Iterator iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()){
                SelectionKey  key = (SelectionKey) iterator.next();
                if (key.isAcceptable()){
                    ServerSocketChannel  server = (ServerSocketChannel) key.channel();
                    SocketChannel socketChannel = server.accept();
                    registeChannel(selector,socketChannel,SelectionKey.OP_READ);
                    sayHello(socketChannel);
                }
                else if (key.isReadable()){
                    System.out.println(" ready to read");
                    readDateFromSocket(key);
                }
                iterator.remove();
            }
        }
    }

    private void registeChannel(Selector selector,SelectableChannel channel , int ops) throws IOException {
        channel.configureBlocking(false);
        channel.register(selector,ops);
    }

    private void sayHello(SocketChannel channel) throws IOException {
        byteBuffer.clear();
        byteBuffer.put("Hello , You Have Connected on Server !".getBytes());
        byteBuffer.flip();
        channel.write(byteBuffer);
    }

    private void readDateFromSocket(SelectionKey key) throws IOException {
        SocketChannel socketChannel = (SocketChannel) key.channel();
        Socket socket = socketChannel.socket();
        int count;
        byteBuffer.clear();
        while ((count = socketChannel.read(byteBuffer))>0 ){
            System.out.println("the buffer size is > 0");
            byteBuffer.flip();
            while (byteBuffer.hasRemaining()){
                System.out.print((char)byteBuffer.get() );
            }
            System.out.println(" on Port :"+ socket.getPort());
            byteBuffer.clear();
        }
        if (count < 0){
            socketChannel.close();
        }
    }
}

java使用epoll默认会使用水平触发,即如果有事件发生,如果你不处理,那么下次还会触发

但经过java 中EPollSelectorImpl实现之后有了小小的变化,如果某个事件发生,你不做任何处理,那么下次调用select的时候,虽然底层epoll仍然会返回事件,但上面的代码会判断本次事件和上次事件是否一致,如果是一样,java认为没有事件发生,如果要做到一致,必须将selectedKeys中的key删掉,否则会有差别,所以请注意selectedKeys删除的重要性!否则会死循环!

posted @ 2015-03-26 13:45  薛定谔的猫_  阅读(286)  评论(0编辑  收藏  举报