论坛首页 入门技术论坛

NIO Web服务器示例

浏览 1628 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-06-25   最后修改:2011-02-13
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 (!Thread.interrupted()) {
        	sel.select();
        	Set<SelectionKey> readyKeys = sel.selectedKeys();
            Iterator<SelectionKey> iter = readyKeys.iterator();  
  
            while (iter.hasNext()) {  
                SelectionKey sk = iter.next();
                if (sk.isAcceptable()) {
                    SocketChannel sc = ssc.accept();  
                    sc.configureBlocking(false);
                    sc.register(sel, SelectionKey.OP_READ).attach(new Worker(sc));
                }else if (sk.isValid() && sk.isReadable()) {
                    Worker worker = (Worker)sk.attachment();
                    if(!worker.isRunning())
                    es.execute(worker);
                }
                readyKeys.clear();
            }  
        }   
    }
      
    private static class Worker implements Runnable{  
        ByteBuffer bb = ByteBuffer.allocateDirect(1024);  
        SocketChannel sc = null;
        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{
        	state = State.RUNNING;
            sc.read(bb);
            bb.flip();  
            byte[] bs = new byte[bb.limit()];  
            bb.get(bs);
            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 Yi Yang\n\n");  
            bb.put(sb.toString().getBytes());
            bb.put("OK".getBytes());
              
            bb.flip();  
            sc.write(bb);
            bb.clear();
            
            sc.close();
        }
        
        public synchronized boolean isRunning(){
        	return state == State.RUNNING;
        }
        
        public synchronized void run() {  
            try {
            	if(state == State.IDLE)
            		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的依据。
论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics