JAVA-实现简单的web服务器


JAVA-实现简单的web服务器

一直以来,我都以为web服务器是一个非常复杂的系统,需要有着高深的理论知识才能去写这么一个软件,它应该是一个团队才可以应付的事情。当然,也想过它的工作原理,无非是绑定一个端口,然后处理web请求并做出相应的响应。

最开始肯定是用socket绑定一个端口,接下来试着从浏览器访问这个端口。没想到,还真能将请求发到这个socket里头来,把请求内容输出以后,发现正是http协议的标准写法,熟悉的GET / HTTP/1.1\r\n 映入了眼帘。在这一刻,我似乎对于web这一回事又有了一个更深刻的认识。浏览器只不过按照http协议的要求,把请求封装成标准格式,打包发送到web服务器上。web服务器将请求收集起来,按照http协议的规定将请求解析,然后把对应的内容找到,又一次按照http协议的要求封装起来,返回给浏览器端。浏览器接下来把这些返回的内容解析,并渲染出来。

package exmaple15;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * Created by summing on 16/10/7.
 * web 服务器
 * 使用socket创建一个web服务器, 使用多线程
 */
public class WebServer {
    // 用public修饰的static成员变量和成员方法本质是全局变量和全局方法
    // 当声明它类的对象时,不生成static变量的副本,而是类的所有实例共享同一个static变量
    public static String WebRoot = "/Users/chenzomi/Downloads";//默认目录
    public static String defaultPage = "index.html";//默认文件

    public static void main(String[] args) throws IOException {
        System.out.println("Server starting...");

        // 使用8888端口提供服务
        ServerSocket server = new ServerSocket(8888);
        while (true) {
            //阻塞, 直到检测有客户端连接(浏览器访问8888端口)
            Socket socket = server.accept();
            System.out.println("Accepting Connection...");

            // 启动服务线程
            new WebThread(socket).start();
        }
    }
}

/*
* Title: 服务子线程
* Description: 使用线程,为多个客户端服务
*/
class WebThread extends Thread {
    private Socket socket;

    /*
    * WebThread 构造器
    * 相当于python里面的init, 运行前执行
    */
    WebThread(Socket socket) {
        this.socket = socket;
    }

    /*
    * TItle: 线程实体
    */
    public void run() {
        InputStream in = null;
        OutputStream out = null;
        try {
            in = socket.getInputStream();//输入流getinputstream,用于读取socket发送过来的数据
            out = socket.getOutputStream();//输出流getoutputstream,用于向socket端发送数据

            // 接收来自浏览器客户端的请求
            Request request = new Request(in);
            // 解析浏览器客户端请求,返回请求的文件地址sURL
            String sURL = request.parse();
            System.out.println("Client Request URL = " + sURL);
            if (sURL.equals("/")) sURL = WebServer.defaultPage;

            // 向发送请求过来的客户端(浏览器)发送文件
            Response response = new Response(out);
            // 发送文件
            response.Send(sURL);

        } catch (IOException e) {
            System.out.println(e.toString());
        } finally {
            System.out.println("Closing Connection...\n");
            //与网络通讯完之后每次都要记得关闭资源
            try {
                if (in != null) in.close();
                if (out != null) out.close();
                if (socket != null) socket.close();
            } catch (IOException e) {

            }
        }
    }
}
package exmaple15;

import com.sun.tools.internal.xjc.Language;
import sun.management.Agent;

import java.io.IOException;
import java.io.InputStream;

/**
 * Created by summing on 16/10/7.
 * Title: 客户请求分析
 * Description: 获取用户HTTP请求, 分析用户所需要的文件
 * Filename: Request.java
 */
public class Request {
    InputStream in = null;

    /*
    * 构造器, 获得输入流, Client的请数据
    * 接收来自客户端的请求
    */
    public Request(InputStream in) {
        this.in = in;
    }

    /*
    * 解析Client的请求
    * 返回类型:String 请求文件字符
    * HTTP服务器请求信息:
    // GET /index.html HTTP/1.1
    // Host: 127.0.0.1:8888
    // Connection: keep-alive
    // Cache-Control: max-age=0
    // Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,//*//*;q=0.8
    // Upgrade-Insecure-Requests: 1
    // User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36
    // Accept-Encoding: gzip, deflate, sdch
    // Accept-Language: en-US,en;q=0.8
    */
    public String parse() {
        //StringBuffer在进行字符串处理时,不生成新的对象,在内存使用上要优于String类
        StringBuffer requestStr = new StringBuffer(2048);

        int i;
        byte[] buffer = new byte[2048];//字节型

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

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

        System.out.println("[requestStr]:\n" + requestStr.toString() + "\n[requestStr END]");
        return getUri(requestStr.toString());
    }

    /*
    * 方法说明:获取URI字符
    * 输入参数:String requestString 请求字符
    * 返回类型:String URI信息字符
    * GET /index.html HTTP/1.1
    */
    private String getUri(String requestString) {
        int index1, index2;
        index1 = requestString.indexOf(' ');
        if (index1 != -1) {
            index2 = requestString.indexOf(' ', index1 + 1);
            if (index2 > index1) {
                System.out.println(index1 + "," + index2);
                return requestString.substring(index1 + 1, index2);
            }
        }
        return null;
    }
}
package exmaple15;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;

/*
 * Created by summing on 16/10/7.
 * Title: 发现HTTP内容和文件内容
 * Description: 获得用户请求后将用户需要的文件读出,添加上HTTP应答头。发送给客户端。
 */
public class Response {
    OutputStream out = null;

    /*
    * 构造器, 获得输出流
    * 向客户端输出数据
    */
    public Response(OutputStream output) {
        this.out = output;
    }

    /*
    * Method:发送信息
    * Input:String 请求的文件名
    */
    public void Send(String ref) throws IOException {
        byte[] bytes = new byte[2048];
        FileInputStream fis = null;

        try {
            //构造文件
            File file = new File(exmaple15.WebServer.WebRoot, ref);
            if (file.exists()) {
                //构造输入文件流
                fis = new FileInputStream(file);
                int ch = fis.read(bytes, 0, 2048);

                //读取文件
                String sBody = new String(bytes, 0);
                //输出信息
                String sendMessage = "HTTP/1.1 200 \r\n" +
                        "Content-Type: text/html\r\n" +
                        "Content-Length: " + ch + "\r\n" +
                        "\r\n" + sBody;

                //输出文件
                out.write(sendMessage.getBytes());
            } else {
                // 找不到文件
                String errorMessage = "HTTP/1.1 404 File Not Found\r\n" +
                        "Content-Type: text/html\r\n" +
                        "Content-Length: 24\r\n" +
                        "\r\n" +
                        "<h1>File not found</h1>";

                out.write(errorMessage.getBytes());
            }
        } catch (Exception e) {
            System.out.println(e.toString());
        } finally {
            if (fis != null) fis.close();
        }
    }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值