NIO学习三、基于NIO的WEB服务器

本文主要是对于NIO的应用,没什么特别的地方。

一、准备过程

     实现的http服务器只可以访问静态资源,需要将文件放在webroot目录下。

二、设计流程:

    1、开发Request进行请求资源的解析,找到请求的路径,如果请求不合法抛出异常。
    2、开发Response将资源返回给客户端
    3、开发HttpServer,创建ServerSocketChannel,获得客户端的SocketChannel进行处理。并将产生异常的请求关闭。

三、具体代码:

HttpServer:
  package com.webserver;


import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

public class HttpServer {
    protected static final String WEB_ROOT=System.getProperty("user.dir")+ File.separator+"webroot";
    protected  static final  int PORT=8080;
    protected  static final  String HOST="127.0.0.1";
    private ServerSocketChannel serverSocketChannel;
    private Selector selector;
    public  static  void main(String args[]){
        HttpServer httpServer=new HttpServer();
        httpServer.run();
    }
    public void run() {
        //开始运行先创建服务器
        if (serverSocketChannel==null) {
            System.out.println("服务器启动。。。。");
            createServer();
        }
        //一直等待创建连接
        while(true) {
            try {
                this.selector.select();//这地方会阻塞等待创建连接
                Set<SelectionKey> sets=this.selector.selectedKeys();
                Iterator<SelectionKey> iterator=sets.iterator();
                ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
                while(iterator.hasNext()){
                    SelectionKey selectionKey=iterator.next();
                    //处理感兴趣的事件
                    dohandelInteresting(selectionKey);
                    iterator.remove();
                }
            } catch (Exception e) {
                System.out.println(e.getMessage());
                continue;
            }
        }
    }

    private void dohandelInteresting(SelectionKey selectionKey)throws Exception{
        if (selectionKey.isAcceptable()){//如果有连接接入那么进行处理

                doHandleLink();//处理连接
        }else if (selectionKey.isReadable()) {//希望请求数据
                SocketChannel socketChannel= (SocketChannel) selectionKey.channel();
            try {
                //处理请求,处理请求的时候可能会发生的异常:请求出错或者
                //远程客户端关闭连接,但服务端还进行操作,这时候统统关闭服务端连接
                doHandleAccess(socketChannel);
            } catch (Exception e) {
                //如果处理请求的过程中发生异常就由服务端取消注册并且关闭它
                socketChannel.close();
                selectionKey.cancel();
                throw  e;
            }
        }
    }
    private void doHandleLink() throws IOException {
        SocketChannel socketChannel=this.serverSocketChannel.accept();

            socketChannel.configureBlocking(false);
            socketChannel.register(selector, SelectionKey.OP_READ);
    }
    //处理请求分为两步,(1)解析请求资源,(2)回送给客户端
    private void doHandleAccess(SocketChannel socketChannel) throws Exception {
            //解析请求
            Request request = doHandleRequest(socketChannel);
            //回送客户端
            doHandleReply(request, socketChannel);
    }

    private void doHandleReply(Request request, SocketChannel socketChannel) throws Exception {
        Response response=new Response(socketChannel,request);
        response.sendStaticResource();
    }

    //处理到来的request请求
    private Request  doHandleRequest(SocketChannel socketChannel) throws Exception {
        Request request=new Request(socketChannel);
        request.doHandelRequestContext();
        return  request;
    }
    //创建服务端
    private void createServer() {
        try {
            this.serverSocketChannel=ServerSocketChannel.open();
            this.serverSocketChannel.socket().bind(new InetSocketAddress(HOST,PORT));
            this.serverSocketChannel.configureBlocking(false);
            createSelector();
            this.serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void createSelector() throws IOException {
        this.selector=Selector.open();
    }
}  

Request:

package com.webserver;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

//接受请求,找出对应的url
public class Request {

    private String requestContext;
    private SocketChannel socketChannel;
    private String url;

    public Request(SocketChannel socketChannel){
        this.socketChannel=socketChannel;
    }

    public String getRequestContext() {
        return requestContext;
    }
    public String getUrl() {
        return url;
    }
    void doHandelRequestContext() throws Exception{
        paserRequestContext();
        paserRequestUrl();
    }

    private void paserRequestContext() throws Exception {
        ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
        byteBuffer.clear();
        byte[]temp=new byte[1024];
        int length=0;
        StringBuilder stringBuilder=new StringBuilder();
        while ((length = socketChannel.read(byteBuffer)) > 0) {
            stringBuilder.append(new String(byteBuffer.array(), 0, length));
        }
        this.requestContext = stringBuilder.toString();
        if (this.requestContext.trim().equals("")) {
            throw new Exception("请求不合法");
        }
    }

    private void paserRequestUrl(){
        int index=requestContext.indexOf(" ");
        if (index!=-1){
           url=requestContext.substring(index+1,requestContext.indexOf(" ",index+1));
        }
        //默认请求/index.html
        if(url.equals("/")){
            url="/index.html";
        }
    }

}

Response

package com.webserver;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;

public class Response {

    private SocketChannel socketChannel;
    private Request request;

    public Response(SocketChannel socketChannel){
        this(socketChannel,null);
    }
    public Response(SocketChannel socketChannel,Request request){
        this.request=request;
        this.socketChannel=socketChannel;
    }
    public void setRequest(Request request) {
        this.request = request;
    }

    public void sendStaticResource() throws Exception {

        FileInputStream fileInputStream=null;
        File file =null;
        ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
        try {
            file= new File(HttpServer.WEB_ROOT, request.getUrl());
            if (file.exists()) {
                fileInputStream = new FileInputStream(file);
                FileChannel fileChannel=fileInputStream.getChannel();
                byteBuffer.put(("HTTP/1.1 200\r\n"
                        + "Content-Type: text/html\r\n"
                        + "Content-Length: "
                        + file.length()
                        + "\r\n"
                        + "\r\n").getBytes());
                byteBuffer.flip();
                socketChannel.write(byteBuffer);
                byteBuffer.clear();
                fileChannel.transferTo(0,fileChannel.size(),socketChannel);
            } else {
                String errorMessage = "HTTP/1.1 404 File Not Found\r\n"
                        + "Content-Type:text/html\r\n"
                        + "Content-Length:23\r\n"
                        + "\r\n"
                        + "<h1>File Not Found</h1>";
                byteBuffer.put(errorMessage.getBytes());
                byteBuffer.flip();
                socketChannel.write(byteBuffer);
                byteBuffer.clear();
                throw new Exception("没找到指定文件");
            }
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        finally {
            if(null!=fileInputStream){
                fileInputStream.close();
            }
        }
    }
}

四、访问
访问结果

ps:如有不对请指出~~~~

 

posted @ 2017-12-05 17:14  十禾。  阅读(231)  评论(0编辑  收藏  举报