java nio

 

java nio:

非阻塞io;

增加了一个角色selector,负责收集客人的需求;

典型的reactor模式的实现,通过注册感兴趣的事件及扫描是否有感兴趣的事件发生,从而做相应的动作;

 

NIO基本成员: 

1. SocketChannel用于建立连接;

2. ServerSocketChannel用于监听连接事件;

3. 通过Selector来获取是否有需要处理的事件;

 

 

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.*;
import java.util.concurrent.ConcurrentHashMap;
import mengka.util.TimeUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *  nio server , 接收client发过来的消息
 *
 */
public class Server {

    private static final Log log = LogFactory.getLog(Server.class);

    private Selector selector;

    private ByteBuffer readBuffer = ByteBuffer.allocate(128);//读取数据的缓存的大小

    private Map<SocketChannel, byte[]> clientMessage = new ConcurrentHashMap<SocketChannel, byte[]>();

    public void start() throws Exception {
        log.info("---------------, server start..");
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        serverChannel.configureBlocking(false);
        serverChannel.bind(new InetSocketAddress(Constant.CHANNEL_CONNECT_IP, Constant.CHANNEL_CONNECT_PORT));

        /**
         *  将channel注册到selector
         */
        selector = Selector.open();
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
            selector.select();
            Set<SelectionKey> keys = selector.selectedKeys();
            Iterator<SelectionKey> keyIterator = keys.iterator();
            while (keyIterator.hasNext()) {
                SelectionKey key = keyIterator.next();
                if (!key.isValid()) {
                    continue;
                }
                if (key.isAcceptable()) {
                    registerClientChannel(key);
                } else if (key.isReadable()) {
                    String message = read(key);
                    log.info("receive message: " + message);
                }
                keyIterator.remove();
            }
        }
    }

    /**
     * 将数据从channel读入buffer
     *
     * @param key
     * @return
     * @throws IOException
     */
    public String read(SelectionKey key) throws IOException {
        SocketChannel socketChannel = (SocketChannel) key.channel();
        this.readBuffer.clear();

        int numRead;
        try {
            numRead = socketChannel.read(this.readBuffer);
        } catch (IOException e) {
            key.cancel();
            socketChannel.close();
            clientMessage.remove(socketChannel);
            return null;
        }

        if (numRead <= 0) {
            log.error("-----------, read data is null!");
            return null;
        }

        clientMessage.put(socketChannel, readBuffer.array());
        String message = "[" + TimeUtil.toDate(new Date(), "yyyy-MM-dd HH:mm:ss") + "]" + new String(readBuffer.array());
        return message;
    }

    /**
     * 将clientChannel注册到selector
     *
     * @param key
     * @throws IOException
     */
    public void registerClientChannel(SelectionKey key) throws IOException {
        log.info("-----------------, register clientChannel to selector...");
        ServerSocketChannel socketChannel = (ServerSocketChannel) key.channel();
        SocketChannel clientChannel = socketChannel.accept();
        clientChannel.configureBlocking(false);
        clientChannel.register(selector, SelectionKey.OP_READ);
    }

}

 

 

Client

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.SocketChannel;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;

/**
 *  NIO非阻塞多线程
 *  <br>
 *  NIO是典型的reactor模式的实现,通过注册感兴趣的事件及扫描是否有感兴趣的事件发生,从而做相应的动作。
 * 
 * @author mengka.hyy
 *
 */
public class Client {

	private static final Log log = LogFactory.getLog(Client.class);

	private Selector selector;

	private SocketChannel socketChannel;

	public void start()throws Exception{
		log.info("---------------, client start..");
		socketChannel = SocketChannel.open();
		socketChannel.configureBlocking(false);
		socketChannel.connect(new InetSocketAddress(Constant.CHANNEL_CONNECT_IP, Constant.CHANNEL_CONNECT_PORT));

		/**
		 *  将channel注册到selector
		 */
		selector = Selector.open();
		socketChannel.register(selector, SelectionKey.OP_CONNECT);

		while(true){
			selector.select();
			Set<SelectionKey> keys = selector.selectedKeys();
			Iterator<SelectionKey> keyIterator = keys.iterator();
			while (keyIterator.hasNext()) {
				SelectionKey key = keyIterator.next();
				if (key.isConnectable()) {
					registerChannel();
					break;
				}else if(key.isWritable()){
					write();
				}
				keyIterator.remove();
			}
		}
	}

	public void registerChannel()throws IOException{
		log.info("-------------, client registerChannel to selector..");
		socketChannel.finishConnect();
		socketChannel.register(selector, SelectionKey.OP_WRITE);
	}

	/**
	 *  发送数据给server
	 *
	 * @throws IOException
	 */
	public void write()throws IOException{
		String message = getInputMessage();
		ByteBuffer writeBuffer = ByteBuffer.wrap(message.getBytes());
		socketChannel.write(writeBuffer);
	}

	public String getInputMessage(){
		System.out.println("please input message");
		Scanner scanner = new Scanner(System.in);
		String message = scanner.nextLine();
		return message;
	}

}

 

public class Constant {

    public static String CHANNEL_CONNECT_IP = "127.0.0.1";

    public static int CHANNEL_CONNECT_PORT = 61111;
}

 

Server server = new Server();
server.start();



Client client = new Client();
client.start();

 

你可能感兴趣的:(java NIO)