NIO Web服务器示例

1 根据cpu core数量确定worker数量
2 selector服务accept和read
3 accept selector作为生产者把获得的请求放入队列
4 当获得read信号时,selector建立工作任务线程worker,并提交给系统线程池
5 worker线程排队后在线程池中执行,把协议头读入缓冲区,然后解析,处理,响应,关闭连接

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.Date;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class WebServer {
private static WebServer svr = new WebServer();
private WebServer(){}
public static WebServer getInstance(){return svr;}

public void init() throws Exception{
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
Selector sel = Selector.open();
ssc.socket().bind(new InetSocketAddress(8088));
ssc.register(sel, SelectionKey.OP_ACCEPT);
ExecutorService es = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

while (sel.isOpen()) {
sel.select();
Set<SelectionKey> readyKeys = sel.selectedKeys();
Iterator<SelectionKey> iter = readyKeys.iterator();

while (iter.hasNext()) {
SelectionKey sk = iter.next();
iter.remove();

try{
if(!sk.isValid()){
continue;
}else if (sk.isAcceptable()) {
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
sc.register(sel, SelectionKey.OP_READ).attach(new Worker(sc));
}else if (sk.isReadable()) {
Worker worker = (Worker)sk.attachment();
if(worker.tryRunning()){
es.execute(worker);
}
}
}catch(Exception ex){
System.err.println(sk.channel());
ex.printStackTrace();
}
}
}
}

private static class Worker implements Runnable{
private ByteBuffer bb = ByteBuffer.allocateDirect(1024);
private SocketChannel sc = null;
private State state = State.IDLE;

private static enum State{
IDLE, RUNNING
}

public Worker(SocketChannel sc){
Thread.currentThread().setName(sc.toString());
this.sc = sc;
}
private void dispose() throws IOException{
sc.read(bb);
bb.flip();
byte[] bs = new byte[bb.limit()];
bb.get(bs);
System.err.println(sc);
System.err.println(new String(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 Aaron Yang\n\n");
bb.put(sb.toString().getBytes());
bb.put(
"<html><head><script></script></head><body><div><h1>Hello World</h1></div></body></html>"
.getBytes());

bb.flip();
sc.write(bb);
bb.clear();

sc.close();
}

public synchronized boolean tryRunning(){
if(state == State.IDLE){
state = State.RUNNING;
return true;
}
return false;
}

public void run() {
try {
dispose();
} catch (IOException e) {
e.printStackTrace();
}
}
}

public static void main(String[] args) throws Exception {
WebServer server = WebServer.getInstance();
server.init();
}
}

===============06/27/10
如何解析header?,以行为单位读取,按照header敏感的关键字进行匹配 对于首行取得对方调用的方法GET/POST 地址 和协议版本
然后根据用户的配置,和解析地址请求,获得响应的servlet,并把通过反射+默认构造函数构造这个servlet,解析地址参数等设置到对象httpservletrequest和httpservletresponse中,然后通过反射invoke对应的get/post/put/delete等方法,并把封装的两个对象作为参数传进去,同时在response的header中传递一个cookie作为session的依据。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值