一步一步实现一个Web Server-01

前言

本次新型冠状病毒的疫情,给本该红火的新年和激情洋溢的2020盖上了一层阴影。作为普通人的我,只能做到听党和国家的话,不添乱,老老实实在家呆着。处理完公司日常工作之余,想着把相关的一些零散知识串联一下,看了一些tomcat相关的架构设计和源码,于是就想,干脆自己尝试写一个简单的server吧。如果你也有兴趣,那我们就开始吧。

本次项目涉及到的一些知识点:

1、http;

2、java反射;

3、java IO;

4、xml解析;

5、Servlet;

6、html基础知识;

7、多线程;

8、java网络编程;

9、NIO

让我们先从一个最基本的java应用开始。曾经有个同事跟我吹嘘,用nodejs几行代码就能搞出一个server来对外提供应用,我们看看用java怎么做:

目标:从浏览器输入一个地址,服务器给我一个反馈信息。

一、http协议

我们的目标是通过浏览器来验证我们的服务器工作状况,所以需要先了解一下基本的http协议。我们先随便来抓一个包看看,http

都包含哪些东西。现在我们就从浏览器F12看一下吧, 后面换成Fiddler来进行查看数据请求的情况,一步步来。

上图中general下包含的就是请求的原始信息,包含了请求方法为Get,请求的url,请求状态,以及远程地址等信息。下方的Response Headers则代表着服务器返回给浏览器的数据的头部信息,也就是说,服务器要给我浏览器返回数据,首先要满足我的协议格式要求,不然ServerA给我返回一个格式,ServerB返回另一个,明天来个C,D,E,F。。好嘛,你们一人一个格式,要把我浏览器累死啊,干脆,大家约定一个格式,你们按照这个给我返回,你嗨我嗨大家嗨!所以呢,我们自己写的服务器,也要按照这个格式给浏览器返回数据,不然人家不认。

前面扯了这么多,下面才真正开始撸码!

搞计算机的各位大神都知道,两个端要想通信,那就需要满足通信三要素:协议,地址,端口。对吧!上面已经定好了协议——http,然后地址暂时就先用我们本机127.0.0.1,端口我们就用8008吧。接下来我们打开IDEA,然后新建一个最最普通的Java项目,根据你们爱好,随便取个名字吧。

然后新建一个Java类,命名为Bootstrap吧,学一把tomcat的命名方式。意思就是这个类将作为我们server的启动入口。既然作为一个服务器,就要有启动,停止两个状态,然后还要对外提供服务,我们就加个doService()方法。这样,这个类的轮廓就出来了:

public class Bootstrap {

    public void start() {
        
    }
    
    public void stop() {
        
    }
    
    public void doService() {
        
    }
    
    public static void main(String[] args) {
        
    }
}

端口号我们作为构造函数的参数传进来,然后ServerSocket和Socket作为成员变量,服务器start的时候,将ServerSocket搞起来。然后就可以对外提供服务了。

            /**创建 ServerSocket*/
            serverSocket = new ServerSocket(port);
            /**拿到socket实例*/
            client = serverSocket.accept();
            /**对外提供服务*/
            doService(client);

服务器关闭的时候,将相关资源释放掉

    /**
     * 服务器关闭,释放掉资源
     */
    public void stop() {
        try {
            serverSocket.close();
            client.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

好了,这样我们的服务器就可以正常启动了。接下来,就是关键的一步,对外提供服务:

我们知道,http的中文名叫超文本传输协议,就是说它比文本更高级,比如能传输图片,还能传歌,传电影,传文件等等。那咋做到的来?我们又知道,计算机这二货就特么认识0和1,所以呢,干脆你们也别传这个传那个呢,我们就按照流的形式来传数据吧,你们传的是啥我不关心,我就认流。那我们就用流的形式传。

        /**获取socket中传输的流*/
        InputStream inputStream = client.getInputStream();
        /**用于接收流数据*/
        byte[] bytes = new byte[1024 * 1024];
        int dataLength = inputStream.read(bytes);
        /**将流数据转化为字符串*/
        String content = new String(bytes,0,dataLength);
        System.out.println(content);

浏览器地址栏输入一把 http://127.0.0.1:8008/ 回车一下,把流给服务器传过来以后,我就接收一波,然后转成人能看懂的东西,就是下面这样:

GET / HTTP/1.1
Host: localhost:8008
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: navigate
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8

这样在服务器端,我们就拿到了客户端传过来的东西。我们的小目标完成一半了,另一半就是回送一些信息给浏览器,礼尚往来嘛!

我们就用最常用的BufferedWriter吧,工具有了,内容呢?前面我们提到,要给浏览器传它能读懂的数据才行,那我们就按照http的协议要求组织呗,先来一段http的头

/**回送一个信息给浏览器,因为要交给浏览器显示,所以要按照http协议的报文格式组织数据*/
        StringBuilder headerInfo = new StringBuilder();
        headerInfo.append("HTTP/1.1 200 OK").append(Constant.CRLF)
                .append("Content-Type: text/html;charset=utf-8").append(Constant.CRLF)
                .append("Date:"+new Date()).append(Constant.CRLF)
                .append("Server: BWS/1.1").append(Constant.CRLF).append(Constant.CRLF);

有了这个头,浏览器就知道了,哦,这是一段http格式的内容,按照http的格式来解析就行了。紧接着就是我们要回送给浏览器的真正内容了

StringBuilder bodyInfo = new StringBuilder();
        bodyInfo.append("<html>").append(Constant.CRLF).append("<body>").append(Constant.CRLF)
                .append("<h1>欢迎使用 Lyn Server ").append("</h1>").append(Constant.CRLF).append("</body>")
                .append("</html>");

好了, 头和内容都有了,输出出去就好了:

bufferedWriter.append(headerInfo).append(bodyInfo);
/**将数据从缓存区刷到浏览器*/
bufferedWriter.flush();

OK,启动服务器,我们来测试一下呢:

浏览器输入:http://localhost:8008/

看控制台:

再看浏览器:

OK,怎么样,用Java搞一个简单的web服务器也很简单吧。当然这只是最小的一步,后面我们不断去完善它,如果你想看全部的源码,请移步全球最大的同性交友网站——https://github.com/justein/lyn-server,本期源码目录 server-main,我们下期再见。

发布了6 篇原创文章 · 获赞 3 · 访问量 2315

猜你喜欢

转载自blog.csdn.net/pengpengchaoren/article/details/104206602