package com.thinker.common.nio;

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.Iterator;

/**
 * nio nio different from bio nio
 *
 * */
public class NioServer{

	private Selector selector;
	/**
	 * 
	 * @param port 监听端口
	 * 初始化服务器
	 *
	 * */
	private NioServer init(int port) throws IOException{
		ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
		serverSocketChannel.configureBlocking(false);
		serverSocketChannel.bind(new InetSocketAddress(port));
		selector = Selector.open();
		//将通道管理器与通道绑定，并为该通道注册SelectionKey.OP_ACCEPT事件
		//只有当该事件到达时Select.select()会返回，否则一直阻塞。
		serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
		return this;
	}
	public void listen() throws IOException{
		System.out.println("service starting.....");
		while(true){
			//当有注册事件到达时方法返回，否则阻塞
			selector.select();
			//获取selector中的迭代器，选中项为注册的事件
			Iterator<SelectionKey> ite = selector.selectedKeys().iterator();
			while(ite.hasNext()){
				SelectionKey key = ite.next();
				//删除已选key，防止重复处理
				ite.remove();
				//客户端连接事件
				if(key.isAcceptable()){
					ServerSocketChannel server = (ServerSocketChannel)key.channel();
					//获取客户端连接通道
					SocketChannel channel = server.accept();
					channel.configureBlocking(false);
					channel.write(ByteBuffer.wrap(new String("send to client").getBytes()));
					channel.register(selector, SelectionKey.OP_READ);
					System.out.println("client connect");
				}else if(key.isReadable()){//有可读数据事件
					//获取客户端传输数据可读消息通道。
					SocketChannel channel = (SocketChannel)key.channel();
					//创建读取数据缓存器
					ByteBuffer buffer = ByteBuffer.allocate(1024);
					int read = channel.read(buffer);
					byte[] data = buffer.array();
					String message = new String(data);

					System.out.println("receive message from client, size:"+buffer.position()+"\tmessage:"+message);
					try{
					Thread.sleep(1000);
					}catch(InterruptedException e){
						e.printStackTrace();
						break;
					}
					ByteBuffer out = ByteBuffer.wrap(new String("hello world").getBytes());
					channel.write(out);
				}
			}
		}
	}
	public static void main(String[] args) {
		try{
			new NioServer().init(1994).listen();
		}catch(IOException e){
			e.printStackTrace();
			System.exit(0);
		}
	}
}
