NIO学习之Web服务器示例
1 根据cpu core数量确定selector数量2 用一个selector服务accept,其他selector按照core-1分配线程数运行
3 accept selector作为生产者把获得的请求放入队列
4 某个selector作为消费者从blocking queue中取出请求socket channel,并向自己注册
5 当获得read信号时,selector建立工作任务线程worker,并提交给系统线程池
6 worker线程排队后在线程池中执行,把协议头读入缓冲区,然后解析,处理,响应,关闭连接
import
java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
public class NioServer {
private static NioServer svr = new NioServer();
private final int numProcessors = Runtime.getRuntime().availableProcessors();
private static LinkedBlockingQueue<SocketChannel> queue = new LinkedBlockingQueue<SocketChannel>();
private static ExecutorService es = Executors.newFixedThreadPool(3);
private NioServer(){}
public static NioServer getInstance(){return svr;}
public void init(){
try {
for(int i=0;i<numProcessors - 1;i++){
Thread tk = new Thread(new Talker());
tk.start();
}
Selector acceptSelector = Selector.open();
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
InetSocketAddress isa = new InetSocketAddress("127.0.0.1", 8080);
ssc.socket().bind(isa);
ssc.register(acceptSelector, SelectionKey.OP_ACCEPT);
while (acceptSelector.select() > 0) {
Set<SelectionKey> readyKeys = acceptSelector.selectedKeys();
Iterator<SelectionKey> i = readyKeys.iterator();
while (i.hasNext()) {
SelectionKey sk = i.next();
i.remove();
if (sk.isAcceptable()) {
ServerSocketChannel nextReady = (ServerSocketChannel) sk
.channel();
SocketChannel s = nextReady.accept();
s.configureBlocking(false);
queue.offer(s);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static class Talker implements Runnable{
private Selector se = null;
public Talker(){
try {
this.se = Selector.open();
} catch (IOException e) {
e.printStackTrace();
}
}
public void addChannelIfAvailable(){
try {
if(queue.isEmpty())
return;
SocketChannel sc = queue.poll();
sc.register(se, SelectionKey.OP_READ);
} catch (ClosedChannelException e) {
e.printStackTrace();
}
}
public void run() {
try {
while (true) {
int skOps = se.select(20);
addChannelIfAvailable();
if(skOps <= 0){
continue;
}
Set<SelectionKey> readyKeys = se.selectedKeys();
Iterator<SelectionKey> i = readyKeys.iterator();
while (i.hasNext()) {
SelectionKey sk = i.next();
i.remove();
if (sk.isValid() && sk.isReadable()) {
SocketChannel sc = (SocketChannel) sk.channel();
sc.configureBlocking(false);
Worker worker = new Worker(sc);
es.execute(worker);
}
}
Thread.sleep(300);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static class Worker implements Runnable{
ByteBuffer bb = ByteBuffer.allocateDirect(1024);
SocketChannel sc = null;
public Worker(SocketChannel sc){
Thread.currentThread().setName(this.toString());
this.sc = sc;
}
public void run() {
try {
try{
sc.read(bb);
}catch(IOException e){
e.printStackTrace();
sc.finishConnect();
sc.close();
return;
}
bb.flip();
byte[] bs = new byte[bb.limit()];
bb.get(bs);
bb.clear();
StringBuilder sb = new StringBuilder();
sb.append("HTTP/1.1 200 OK").append("\n").append("Date:" + new Date()).append("\n");
sb.append("Server:NIO Server By Yi Yang\n\n");
bb.put(sb.toString().getBytes());
bb.flip();
sc.write(bb);
bb.clear();
FileInputStream is = new FileInputStream("E:/test.html");
is.getChannel().transferTo(0, 1024, sc);
is.close();
sc.finishConnect();
sc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws Exception {
NioServer server = NioServer.getInstance();
server.init();
}
}
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
public class NioServer {
private static NioServer svr = new NioServer();
private final int numProcessors = Runtime.getRuntime().availableProcessors();
private static LinkedBlockingQueue<SocketChannel> queue = new LinkedBlockingQueue<SocketChannel>();
private static ExecutorService es = Executors.newFixedThreadPool(3);
private NioServer(){}
public static NioServer getInstance(){return svr;}
public void init(){
try {
for(int i=0;i<numProcessors - 1;i++){
Thread tk = new Thread(new Talker());
tk.start();
}
Selector acceptSelector = Selector.open();
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
InetSocketAddress isa = new InetSocketAddress("127.0.0.1", 8080);
ssc.socket().bind(isa);
ssc.register(acceptSelector, SelectionKey.OP_ACCEPT);
while (acceptSelector.select() > 0) {
Set<SelectionKey> readyKeys = acceptSelector.selectedKeys();
Iterator<SelectionKey> i = readyKeys.iterator();
while (i.hasNext()) {
SelectionKey sk = i.next();
i.remove();
if (sk.isAcceptable()) {
ServerSocketChannel nextReady = (ServerSocketChannel) sk
.channel();
SocketChannel s = nextReady.accept();
s.configureBlocking(false);
queue.offer(s);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static class Talker implements Runnable{
private Selector se = null;
public Talker(){
try {
this.se = Selector.open();
} catch (IOException e) {
e.printStackTrace();
}
}
public void addChannelIfAvailable(){
try {
if(queue.isEmpty())
return;
SocketChannel sc = queue.poll();
sc.register(se, SelectionKey.OP_READ);
} catch (ClosedChannelException e) {
e.printStackTrace();
}
}
public void run() {
try {
while (true) {
int skOps = se.select(20);
addChannelIfAvailable();
if(skOps <= 0){
continue;
}
Set<SelectionKey> readyKeys = se.selectedKeys();
Iterator<SelectionKey> i = readyKeys.iterator();
while (i.hasNext()) {
SelectionKey sk = i.next();
i.remove();
if (sk.isValid() && sk.isReadable()) {
SocketChannel sc = (SocketChannel) sk.channel();
sc.configureBlocking(false);
Worker worker = new Worker(sc);
es.execute(worker);
}
}
Thread.sleep(300);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static class Worker implements Runnable{
ByteBuffer bb = ByteBuffer.allocateDirect(1024);
SocketChannel sc = null;
public Worker(SocketChannel sc){
Thread.currentThread().setName(this.toString());
this.sc = sc;
}
public void run() {
try {
try{
sc.read(bb);
}catch(IOException e){
e.printStackTrace();
sc.finishConnect();
sc.close();
return;
}
bb.flip();
byte[] bs = new byte[bb.limit()];
bb.get(bs);
bb.clear();
StringBuilder sb = new StringBuilder();
sb.append("HTTP/1.1 200 OK").append("\n").append("Date:" + new Date()).append("\n");
sb.append("Server:NIO Server By Yi Yang\n\n");
bb.put(sb.toString().getBytes());
bb.flip();
sc.write(bb);
bb.clear();
FileInputStream is = new FileInputStream("E:/test.html");
is.getChannel().transferTo(0, 1024, sc);
is.close();
sc.finishConnect();
sc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws Exception {
NioServer server = NioServer.getInstance();
server.init();
}
}
===============06/27/10
如何解析header?,以行为单位读取,按照header敏感的关键字进行匹配 对于首行取得对方调用的方法GET/POST 地址 和协议版本
然后根据用户的配置,和解析地址请求,获得响应的servlet,并把通过反射+默认构造函数构造这个servlet,解析地址参数等设置到对象httpservletrequest和httpservletresponse中,然后通过反射invoke对应的get/post/put/delete等方法,并把封装的两个对象作为参数传进去,同时在response的header中传递一个cookie作为session的依据。
如何解析header?,以行为单位读取,按照header敏感的关键字进行匹配 对于首行取得对方调用的方法GET/POST 地址 和协议版本
然后根据用户的配置,和解析地址请求,获得响应的servlet,并把通过反射+默认构造函数构造这个servlet,解析地址参数等设置到对象httpservletrequest和httpservletresponse中,然后通过反射invoke对应的get/post/put/delete等方法,并把封装的两个对象作为参数传进去,同时在response的header中传递一个cookie作为session的依据。
@2008 杨一. 版权所有. 保留所有权利