一个基于java的web服务器实现主要使用这两个重要的类:java.net.Socket和java.net.ServerSocket,并通过HTTP消息进行通信。

HTTP请求


一个HTTP请求包括三个组成部分:

1.方法—统一资源标示符(URI)—协议/版本

2.请求的头部

3.主体内容


GET / HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: zh-CN,zh;q=0.8



HTTP响应

类似于HTTP请求,一个HTTP响应也包括三个组成部分:

1.方法-统一资源标示符(URI)-协议/版本

2.响应的头部

3.主体内容

下面是一个HTTP响应的例子:

HTTP/1.1 200 OK  
Server: IBM/4.0  
Date: Sat, 6 Nov 2013 13:13:00 GMT  
Content-Type: text/html  
Last-Modified: Sat, 5 Jan 2013 13:13:12 GMT  
Content-Length: 112



socket类


套接字是网络连接的一个端点。套接字使得一个应用可以从网络中读取和写入数据。放在两个不同的计算机上的两个应用可以通过连接发送和接受字节流。为了从你的应用发送一条信息到另一个应用,你需要指导另一个应用的IP地址和套接字端口。

ServerSocket类

Socket类代表一个客户端套接字,即任何时候你想连接到一个远程服务器应用的时候你构造的套接字。如果是一个服务器程序依靠Socket类是行不通的。你的服务器必须随时待命,因为客户端何时想你发送请求是不知道的。

ServerSocket和Socket不同,服务器套接字的角色是等待来自客户端的连接请求。一旦服务器套接字获得一个连接请求,它创建一个Socket实例来与客户端进行通信。

下面是一个简单的HTTP请求的实现:

先创建一个HTTPSERVER服务

public class HttpServer {
    public static final String WEB_ROOT =  "d:/webroot";

    private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";

    private boolean shutdown = false;

    public static void main(String[] args) {
        HttpServer server = new HttpServer();
        server.await();
    }

    public void await() {

        ServerSocket serverSocket = null;

        int port = 8080;

        try {
            serverSocket = new ServerSocket(port, 1, InetAddress
                    .getByName("127.0.0.1"));
        } catch (UnknownHostException e) {

            e.printStackTrace();

        } catch (IOException e) {

            e.printStackTrace();
            System.exit(1);

        }

        // Loop waiting for a request
        while (!shutdown) {

            Socket socket = null;
            InputStream input = null;
            OutputStream output = null;

            try {
                socket = serverSocket.accept();
                input = socket.getInputStream();
                output = socket.getOutputStream();

                // create Request object and parse
                Request request = new Request(input);
                request.parse();

                // create Response object
                Response response = new Response(output);
                response.setRequest(request);
                response.sendStaticResource();

                // Close the socket;
                socket.close();

                // check if the revious URI is a shutdown command
                shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
            } catch (IOException e) {

                e.printStackTrace();
                continue;

            }

        }

    }
}



对应服务要有请求

public class Request {
    private InputStream input;

    private String uri;

    public Request(InputStream input) {
        this.input = input;
    }

    public void parse() {
        // Read a set of characters from the socket
        StringBuffer request = new StringBuffer(2018);

        int i;
        byte[] buffer = new byte[2048];

        try {
            i = input.read(buffer);
        } catch (IOException e) {
            e.printStackTrace();
            i = -1;
        }

        for (int j = 0; j < i; j ++) {
            request.append((char)buffer[j]);
        }

        System.out.println("-----------------request----------------");
        System.out.print(request.toString());

        uri = parseUri(request.toString());
    }

    private String parseUri(String requestString) {

        int index1, index2;
        index1 = requestString.indexOf(' ');
        if (index1 != -1) {
            index2 = requestString.indexOf(' ', index1 + 1);
            return requestString.substring(index1 + 1, index2);
        }
        return null;

    }

    public String getUri() {

        return uri;
    }
}



对应请求要有响应

public class Response {

    private static final int BUFFER_SIZE = 1024;

    private Request request;
    private OutputStream output;

    public Response(OutputStream output) {
        this.output = output;
    }

    public void setRequest(Request request) {
        this.request = request;
    }

    public void sendStaticResource() throws IOException {
        byte[] bytes = new byte[BUFFER_SIZE];
        FileInputStream fis = null;
        boolean errorFlag = true;
        if(request.getUri()!=null){
            File file = new File(HttpServer.WEB_ROOT, request.getUri());
            if (file.exists()) {
                fis = new FileInputStream(file);
                int ch = fis.read(bytes, 0, BUFFER_SIZE);
                while (ch != -1) {
                    output.write(bytes, 0, ch);
                    ch = fis.read(bytes, 0, BUFFER_SIZE);
                }
                errorFlag = false;
            }
        }
        if(errorFlag) {
            // file not found
            String errorMessage = "HTTP/1.1 404 File NOT Fount\r\n" +
                    "Content-Type: text/html\r\n" +
                    "Content-Length: 23\r\n" +
                    "\r\n" +
                    "<h1>File Not Found</h1>";
            output.write(errorMessage.getBytes());
        }
        if (fis != null) {
            fis.close();
        }
    }
}



以上三个简单的类创建好后,我们可以启动HttpServer,然后在浏览器上输入127.0.0.1:8080 可以看见一个File Not Found,如果想有结果输出到页面上,请配置一个文件在webroot下,例如建一个order.txt,在里面写些内容,也可以弄一个html,这样就可以在页面上显示你所要看的页面,请求方式就是http://

127.0.0.1:8080/order.txt

若想关闭此服务则调用http://127.0.0.1:8080/SHUTDOWN 即可