以前一直用的是“ervery thread per connection”的服务器端模式,今天试了下NIO非阻塞模式的服务器。 不过java不能实现I/O完成端口模型,这点很遗憾
packagecom.vista.Server;

importjava.io.IOException;
importjava.net.InetSocketAddress;
importjava.net.ServerSocket;
importjava.nio.ByteBuffer;
importjava.nio.channels.SelectionKey;
importjava.nio.channels.Selector;
importjava.nio.channels.ServerSocketChannel;
importjava.nio.channels.SocketChannel;
importjava.util.Iterator;
importjava.util.LinkedList;
importjava.util.Set;

publicclassSelectorServer


{
privatestaticintDEFAULT_SERVERPORT=6018;//默认端口
privatestaticintDEFAULT_BUFFERSIZE=1024;//默认缓冲区大小为1024字节
privateServerSocketChannelchannel;
privateLinkedList<SocketChannel>clients;
privateSelectorreadSelector;
privateByteBufferbuffer;//字节缓冲区
privateintport;

publicSelectorServer(intport)throwsIOException


{
this.port=port;
this.clients=newLinkedList<SocketChannel>();
this.channel=null;
this.readSelector=Selector.open();//打开选择器
this.buffer=ByteBuffer.allocate(DEFAULT_BUFFERSIZE);
}
//服务器程序在服务循环中调用sericeClients()方法为已接受的客户服务
publicvoidserviceClients()throwsIOException


{
Setkeys;
Iteratorit;
SelectionKeykey;
SocketChannelclient;
//在readSelector上调用select()方法,参数1代表如果调用select的时候那么阻塞最多1秒钟等待可用的客户端连接
if(readSelector.select(1)>0)


{
keys=readSelector.selectedKeys();//取得代表端通道的键集合
it=keys.iterator();
//遍历,为每一个客户服务
while(it.hasNext())


{
key=(SelectionKey)it.next();
if(key.isReadable())


{//如果通道可读,那么读此通道到buffer中
intbytes;
client=(SocketChannel)key.channel();//取得键对应的通道
buffer.clear();//清空缓冲区中的内容,设置好position,limit,准备接受数据
bytes=client.read(buffer);//从通道中读数据到缓冲中,返回读取得字节数
if(bytes>=0)


{
buffer.flip();//准备将缓冲中的数据写回到通道中
client.write(buffer);//数据写回到通道中
}
elseif(bytes<0)


{//如果返回小于零的值代表读到了流的末尾
clients.remove(client);
//通道关闭时,选择键也被取消
client.close();
}
}
}
}
}

publicvoidregisterClient(SocketChannelclient)throwsIOException


{//配置和注册代表客户连接的通道对象
client.configureBlocking(false);//设置此通道使用非阻塞模式
client.register(readSelector,SelectionKey.OP_READ);//将这个通道注册到选择器上
clients.add(client);//保存这个通道对象
}
publicvoidlisten()throwsIOException


{//服务器开始监听端口,提供服务
ServerSocketsocket;
SocketChannelclient;
channel=ServerSocketChannel.open();//打开通道
socket=channel.socket();//得到与通到相关的socket对象
socket.bind(newInetSocketAddress(port),10);//将scoket榜定在制定的端口上
//配置通到使用非阻塞模式,在非阻塞模式下,可以编写多道程序同时避免使用复杂的多线程
channel.configureBlocking(false);
try


{
while(true)


{//与通常的程序不同,这里使用channel.accpet()接受客户端连接请求,而不是在socket对象上调用accept(),这里在调用accept()方法时如果通道配置为非阻塞模式,那么accept()方法立即返回null,并不阻塞
client=channel.accept();
if(client!=null)


{
registerClient(client);//注册客户信息
}
serviceClients();//为以连接的客户服务
}
}
finally


{
socket.close();//关闭socket,关闭socket会同时关闭与此socket关联的通道
}
}
publicstaticvoidmain(String[]args)throwsIOException


{
System.out.println("服务器启动
");
SelectorServerserver=newSelectorServer(SelectorServer.DEFAULT_SERVERPORT);
server.listen();//服务器开始监听端口,提供服务


}

}
















































































































































修改版本:
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->
packagecom.vista.Server;

importjava.io.BufferedWriter;
importjava.io.FileInputStream;
importjava.io.IOException;
importjava.io.OutputStreamWriter;
importjava.io.PrintWriter;
importjava.net.InetSocketAddress;
importjava.net.ServerSocket;
importjava.nio.ByteBuffer;
importjava.nio.CharBuffer;
importjava.nio.channels.FileChannel;
importjava.nio.channels.SelectionKey;
importjava.nio.channels.Selector;
importjava.nio.channels.ServerSocketChannel;
importjava.nio.channels.SocketChannel;
importjava.nio.charset.Charset;
importjava.nio.charset.CharsetDecoder;
importjava.util.Iterator;
importjava.util.LinkedList;
importjava.util.Set;

publicclassSelectorServer


{
privatestaticintDEFAULT_SERVERPORT=6018;//默认端口
privatestaticintDEFAULT_BUFFERSIZE=1024;//默认缓冲区大小为1024字节
privatestaticStringDEFAULT_CHARSET="GB2312";//默认码集
privatestaticStringDEFAULT_FILENAME="bigfile.dat";
privateServerSocketChannelchannel;
privateLinkedList<SocketChannel>clients;
privateSelectorselector;//选择器
privateByteBufferbuffer;//字节缓冲区
privateintport;
privateCharsetcharset;//字符集
privateCharsetDecoderdecoder;//解码器


publicSelectorServer(intport)throwsIOException


{
this.port=port;
this.clients=newLinkedList<SocketChannel>();
this.channel=null;
this.selector=Selector.open();//打开选择器
this.buffer=ByteBuffer.allocate(DEFAULT_BUFFERSIZE);
this.charset=Charset.forName(DEFAULT_CHARSET);
this.decoder=this.charset.newDecoder();

}

privateclassHandleClient


{
privateStringstrGreeting="welcometoVistaQQ";
publicHandleClient()throwsIOException


{
}
publicStringreadBlock()


{//读块数据
returnthis.strGreeting;
}
publicvoidclose()


{

}
}

protectedvoidhandleKey(SelectionKeykey)throwsIOException


{//处理事件
if(key.isAcceptable())


{//接收请求
ServerSocketChannelserver=(ServerSocketChannel)key.channel();//取出对应的服务器通道
SocketChannelchannel=server.accept();
channel.configureBlocking(false);
channel.register(selector,SelectionKey.OP_READ);//客户socket通道注册读操作
}
elseif(key.isReadable())


{//读信息
SocketChannelchannel=(SocketChannel)key.channel();
intcount=channel.read(this.buffer);
if(count>0)


{
this.buffer.flip();
CharBuffercharBuffer=decoder.decode(this.buffer);
System.out.println("Client>>"+charBuffer.toString());
SelectionKeywKey=channel.register(selector,
SelectionKey.OP_WRITE);//为客户sockt通道注册写操作
wKey.attach(newHandleClient());
}
else


{//客户已经断开
channel.close();
}
this.buffer.clear();//清空缓冲区
}
elseif(key.isWritable())


{//写事件
SocketChannelchannel=(SocketChannel)key.channel();
HandleClienthandle=(HandleClient)key.attachment();//取出处理者
ByteBufferblock=ByteBuffer.wrap(handle.readBlock().getBytes());
channel.write(block);
//channel.socket().getInputStream().(block);
//PrintWriterout=newPrintWriter(newBufferedWriter(newOutputStreamWriter(
//channel.socket().getOutputStream())),true);
//out.write(block.toString());

}

}
publicvoidlisten()throwsIOException


{//服务器开始监听端口,提供服务
ServerSocketsocket;
channel=ServerSocketChannel.open();//打开通道
socket=channel.socket();//得到与通到相关的socket对象
socket.bind(newInetSocketAddress(port));//将scoket榜定在制定的端口上
//配置通到使用非阻塞模式,在非阻塞模式下,可以编写多道程序同时避免使用复杂的多线程
channel.configureBlocking(false);
channel.register(selector,SelectionKey.OP_ACCEPT);
try


{
while(true)


{//与通常的程序不同,这里使用channel.accpet()接受客户端连接请求,而不是在socket对象上调用accept(),这里在调用accept()方法时如果通道配置为非阻塞模式,那么accept()方法立即返回null,并不阻塞
this.selector.select();
Iteratoriter=this.selector.selectedKeys().iterator();
while(iter.hasNext())


{
SelectionKeykey=(SelectionKey)iter.next();
iter.remove();
this.handleKey(key);

}
}
}
catch(IOExceptionex)


{
ex.printStackTrace();
}
}
publicstaticvoidmain(String[]args)throwsIOException


{
System.out.println("服务器启动
");
SelectorServerserver=newSelectorServer(SelectorServer.DEFAULT_SERVERPORT);
server.listen();//服务器开始监听端口,提供服务
}

}





















































































































































































