通过socket相关接口和http的访问协议做一个简单的web服务器

作者: admin 分类: Tomcat,网络协议 发布时间: 2019-11-08 15:31  阅读: 23 views

对网络中的各种协议认识不足,所以学习下。在学习tomcat服务器的过程中,了解到它是基于一个简单的web服务器慢慢拓展到一个应用广泛的服务器的。

所以,这里做个简单的web服务器

  1. 创建一个简答的webserver类
package com.chl.webserver;

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;

/**
 * 一个简单的web服务器( Tomcat )
 * @author chenhailong
 *
 */
public class WebServer {

    /**
     * 可以存放一些测试应用程序的静态资源或servlet.是工作目录
     */
    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) {


        WebServer ws = new WebServer();
        ws.await();

    }

    //socket服务端一直接收消息
    public void await() {
        ServerSocket serverSocket = null;
        int port = 8080;
        try {
            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 {
                //接收到请求之后,await方法从accept方法返回的socket实例中获取input、output对象
                socket = serverSocket.accept();
                input = socket.getInputStream();
                output = socket.getOutputStream();

                //创建一个Request对象并且调用parse方法解析HTTP请求的原始数据
                Request request = new Request(input);
                request.parse();

                //创建一个Response响应对象
                Response response = new Response(output);
                response.setRequest(request);
                response.sendStaticResource();

                //关闭socket
                socket.close();
                // 判断http请求的uri是不是一个shutdown命令。如果是,则shutdown会置为true,从而推出循环
                shutdown = request.getUri().equals(SHUTDOWN_COMMAND);

            }catch(Exception e) {
                e.printStackTrace();
                continue;
            }

        }
    }

}


  1. 创建一个简单的request请求类
package com.chl.webserver;

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

public class Request {
    // 输入流
    private InputStream input;
    // 地址
    private String uri;

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

    public String getUri() {
        return uri;
    }

    //解析http请求中的原始数据。
    void parse() {
         //Read a set of characters from the socket
         StringBuffer request = new StringBuffer(2048);
         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.toString());
         uri = parseUri(request.toString());
     }

    //从 url中返回uri
    private String parseUri(String requestString) {
        int index1 , index2;
        index1 = requestString.indexOf(" ");
        if(index1 != -1) {
            index2 = requestString.indexOf(" ", index1 + 1);
            if(index2 > index1) {
                return requestString.substring(index1+1, index2);
            }
        }
        return null;
    }
}


3.创建一个response响应类

package com.chl.webserver;

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;

    Request request;
    OutputStream output;

    //构造函数创建output对象
    public Response(OutputStream output) {
        this.output = output;
    }

    //传递request对象给reponse
    public void setRequest(Request request) {
        this.request = request;
    }

    // 输出一个静态资源
    public void sendStaticResource() throws IOException{
        byte[] bytes = new byte[BUFFER_SIZE];
        FileInputStream fis = null;
        try {
            File file = new File(WebServer.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,BUFFER_SIZE);
                    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>";
                System.out.println(errorMessage);
                output.write(errorMessage.getBytes());
            }


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

  1. 测试输入 http://127.0.0.1:8080/123

可以看到控制台输出以下信息


## 请求信息 GET /123 HTTP/1.1 Host: 127.0.0.1:8080 Connection: keep-alive Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 ## 响应信息 HTTP/1.1 404 File Not Found Content-Type : text/html Content-Length:23 <h1>File Not Found</h1>

5.关闭服务 输入http://127.0.0.1:8080/SHUTDOWN

你查看后台,就发现服务已经关闭了。

注:这是一个简单的例子,由繁入简容易,由简入繁可是需要很多的尝试及验证才能证明它的能力。所以还是很佩服这些能写服务器、各种如dubbo协议、hession制定人,能力很强且创造力满满。我们这些造轮子的就明显相形见绌。

扩展:
了解RPC逻辑及SOCKET的使用请看这里


   原创文章,转载请标明本文链接: 通过socket相关接口和http的访问协议做一个简单的web服务器

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

发表评论

电子邮件地址不会被公开。 必填项已用*标注

更多阅读