selector使用
package Demo4;
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 是可以使用单个线程连接多个客户端,开销小
*
* @author Douglasli
*
*/
public class NioServer {
//通道管理器
private Selector selector;
/**
* 初始化一个ServerSocket通道
* @param port 端口号
* @throws IOException
*/
public void initServer(int port) throws IOException
{
//获得一个ServerSocket通道
ServerSocketChannel serverChannel = ServerSocketChannel.open();
//设置通道为非阻塞(必须设置为false)
serverChannel.configureBlocking(false);
//将该通道对应的ServerSocket绑定到port端口
serverChannel.socket().bind(new InetSocketAddress(port));
//获得一个通道管理器
this.selector = Selector.open();
//将通道管理器和通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
}
/**
* 采用轮询的方式监听selector上是否有需要处理的时间
* @throws IOException selector.select()方法抛的异常
*/
public void listen() throws IOException{
System.out.println("NIOServer start");
while(true)
{
//当注册的事件到达时,方法返回,否则,该方法一直阻塞
//select()方法返回的int值表示有多少通道已经就绪,每次select()方法调用之间,只有一个通道就绪了,所以本案例中这个n只会等于1
int n = selector.select();
System.out.println(n);
Iterator<?> it = this.selector.selectedKeys().iterator();
while(it.hasNext())
{
SelectionKey key = (SelectionKey)it.next();
it.remove();
handler(key);
}
}
}
public void handler(SelectionKey key) throws IOException
{
//客户端 请求连接事件
if(key.isAcceptable())
{
handlerAccept(key);
}else if(key.isReadable())
{
handlerRead(key);
}
}
//
private void handlerAccept(SelectionKey key) throws IOException {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
//获得和客户端连接的通道
SocketChannel channel = server.accept();
channel.configureBlocking(false);
System.out.println("client link success!!!!");
//在和客户端连接成功之后,为了可以接收到客户端的信息,需要给通道设置读的权限。
channel.register(this.selector, SelectionKey.OP_READ);
}
//读取从客户端发来的消息,并且做出响应,
private void handlerRead(SelectionKey key) {
try {
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer buf = ByteBuffer.allocate(1024);
int read = channel.read(buf);
if(read>0)
{
byte[] data = buf.array();
String msg = new String(data).trim();
System.out.println("server msg:"+ msg);
//回写数据给客户端
ByteBuffer out = ByteBuffer.wrap(msg.getBytes());
channel.write(out);
}else{
System.out.println("client close,no msg accept in Server");
key.cancel();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
NioServer server = new NioServer();
server.initServer(8000);
server.listen();
}
}
上面例子测试:
运行上述Demo,即是启动NIOServer服务器。
启动telnet客户端 :cmd 命令窗口 telnet 127.0.0.1 8000,会出现命令窗口什么都没有的情况(如左图),请接着按下CTRL+]快捷键即可(如右图)。
eclipse测试台结果: