一个简单的Web服务器(Web服务器如何工作)

来源:互联网 发布:我们来了网络更新时间 编辑:程序博客网 时间:2024/05/19 09:03

       HTTP允许Web服务器和浏览器通过Internet发送并接收数据,是一种基于“请求——响应”的协议。HTTP使用的是可靠的TCP连接,TCP协议默认使用TCP 80端口。在HTTP中,总是由客户端通过建立连接并发送HTTP请求来初始化一个事务的。Web服务器端并不负责联系客户端或建立一个到客户端的回调连接。HTTP协议是无状态的协议。        套接字是网络连接的端点。套接字使应用程序可以从网络中读取数据,可以向网络中写入数据。不同计算机上的两个应用程序可以通过连接发送或接收字节流,一次达到相互通信的目的。要创建一个套接字,需要指明其主机名和端口号,如下:

new Socket("www.baidu.com", 80);
一旦创建了Socket的实例,就可以使用该实例发送或接收字节流。要发送字节流,需要调用Socket类的getOutputStream()方法获取一个java.io.OutputStream对象。要发送文本到远程应用程序,通常需要使用返回的OutputStream对象创建一个java.io.PrintWriter对象。若想要从连接的另一端接收字节流,需要调用Socket类的getInputStream()方法,该方法会返回一个java.io.InputStream对象。

如果要想实现一个服务器应用程序,需要使用服务器套接字的实现(java.net.ServerSocket)。ServerSocket类和Socket类不同,服务器套接字要等待来自客户端的连接请求,当服务器套接字收到了连接请求以后,他会创建一个Socket实例来处理与客户端的通信。要创建一个服务器套接字,需要指定其主机名和监听的端口号。服务器套接字还有一个重要属性是backlog,表示在服务器在拒绝接受传入的请求之前,传入的连接请求的最大队列长度。ServerSocket类的实例化方式之一如下:

new ServerSocket(8080, 1, InetAddress.getByName("127.0.0.1"));
创建了ServletSocket实例后,可以使其等待传入的连接请求,该链接请求会通过服务器套接字侦听的端口上绑定地址传入。这些工作可以通过调用ServerSocket类的accept方法完成。只有当接收到连接请求时,该方法才会返回,返回值是一个Socket实例。

Web服务器应用程序实例如下:

1.Request类:

package com.demo.tomcat;import java.io.IOException;import java.io.InputStream;public class Request {    /**     * 从Socket中读取数据的缓冲区大小     */    private static final int SOCKET_BUFFER_SIZE = 1024;    /**     * 输入流(通过与客户端通信Socket中获取)     */    private InputStream input;    /**     * Http请求的URI     */    private String uri;    /**     * Constructor     * @param input 输入流     */    public Request(InputStream input){        this.input = input;    }    /**     * 解析Http请求的原始数据(例如,GET请求index.html的请求行为:"GET /index.html HTTP/1.1)     */    public void parse(){        //读取Socket中的数据        StringBuffer sb = new StringBuffer(SOCKET_BUFFER_SIZE);        int i;        byte[] buf = new byte[SOCKET_BUFFER_SIZE];        try {            i = input.read(buf);            for(int j = 0; j < i; j++){                sb.append((char) buf[j]);            }        } catch (IOException e) {            e.printStackTrace();        }        //解析URI        if(sb.length() > 0){            uri = parseURI(sb.toString());        }    }    /**     * 获取请求的URI     * @param requestStr     * @return     */    private String parseURI(String requestStr){        if(requestStr == null || requestStr.length() <= 0){            return null;        }        int index1,index2;        index1 = requestStr.indexOf(' ');        if(index1 != -1){            index2 = requestStr.indexOf(' ', index1 + 1);            if(index2 > index1){                //截取字符串并返回                return requestStr.substring(index1 + 1, index2);            }        }        return null;    }    public String getUri() {        return uri;    }}

2.Response类:

package com.demo.tomcat;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.OutputStream;public class Response {    /**     * 读取数据缓冲区大小     */    private static final int BUFFER_SIZE = 1024;    /**     * 请求     */    private Request request;    /**     * 输出流     */    private OutputStream output;    /**     * Constructor     * @param output 输出流     */    public Response(OutputStream output){        this.output = output;    }    public void setRequest(Request request){        this.request = request;    }    /**     * 发送一个静态资源到浏览器     * @throws Exception     */    public void sendStaticResource() throws Exception {        //读取静态资源        byte[] bytes = new byte[BUFFER_SIZE];        FileInputStream fis = null;        try {            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);                }            } 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>";                //发送错误信息                output.write(errorMessage.getBytes());            }        } catch (IOException e) {            e.printStackTrace();        } finally {            fis.close();        }    }}

3.HttpServer类:

package com.demo.tomcat;import java.io.File;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.InetAddress;import java.net.ServerSocket;import java.net.Socket;public class HttpServer {    /**     * 访问的根路径     */    public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot";    /**     * 关闭服务请求命令     */    public static final String SHUTDOWN_COMMAND = "/SHUTDOWN";    /**     * 是否关闭服务     */    private Boolean shutdown = false;    public static void main(String[] args){        HttpServer httpServer = new HttpServer();        httpServer.await();    }    /**     * 从accept方法返回的Socket中获取InputStream对象和OutputStream对象     */    public void await(){        //创建ServerSocket对象        ServerSocket serverSocket = null;        //监听端口        int port = 8080;        try {            //实例化ServerSocket对象            serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));        } catch (IOException e) {            e.printStackTrace();            System.exit(1);        }        while(!shutdown){            Socket socket = null;            InputStream input = null;            OutputStream output = null;            try {                socket = serverSocket.accept();                input = socket.getInputStream();                output = socket.getOutputStream();                //创建并解析request                Request request = new Request(input);                request.parse();                //创建response,发送静态资源给浏览器                Response response = new Response(output);                response.setRequest(request);                response.sendStaticResource();                //关闭socket                socket.close();                //是否关闭服务                shutdown = request.getUri().equals(SHUTDOWN_COMMAND);            } catch (Exception e) {                e.printStackTrace();            }        }    }}

注意:需要在项目所在的路径下添加一个名为"webroot"的文件夹,该文件夹下放置你要访问你的文件(如test.txt),输入相应的URI(如http://lcoalhost:8080/test.txt),即可访问到该资源文件。

参考:深入剖析Tomcat第一章


原创粉丝点击