博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《深度解析Tomcat》 第一章 一个简单的Web服务器
阅读量:5014 次
发布时间:2019-06-12

本文共 8250 字,大约阅读时间需要 27 分钟。

本章介绍Java Web服务器是如何运行的。从中可以知道Tomcat是如何工作的。

基于Java的Web服务器会使用java.net.Socket类和java.net.ServerSocket类这两个类,并通过发送HTTP消息进行通信。

因此,本章先介绍HTTP协议和这两个类。然后介绍一个简单的Web服务器。

1.1 HTTP协议

HTTP请求和相应信息

略。

1.2 Socket类

1.2.1 Socket类

Socket类表示一个客户端套接字(socket),即想要连接远程服务器应用程序时创建的套接字。

public Socket(String host, int port);//参数host是远程主机的名称或IP地址,参数port是连接远程应用程序的端口号。// 例如,想要通过80端口连接yahoo.com,可以使用以下语句创建Socket对象:new Socket("yahoo.com". 80);

一旦成功创建了Socket类的实例,就可以使用该实例发送或接收字节流。代码示例:

package demo;import java.io.*;import java.net.Socket;public class SocketDemo {    public static void main(String[] args) {        try {            Socket socket = new Socket("127.0.0.1", 8080);            OutputStream os = socket.getOutputStream();            boolean autoFlush = true;            PrintWriter out = new PrintWriter(socket.getOutputStream(), autoFlush);            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));            // 发送一个HTTP请求到服务器            out.println("GET /index.jsp HTTP/1.1");            out.println("Host: localhost:8080");            out.println("Connection: Close");            out.println();            // 读取响应            boolean loop = true;            StringBuffer sb = new StringBuffer(8096);            while (loop) {                if (in.ready()) {                    int i=0;                    while (i != -1) {                        i = in.read();                        sb.append((char) i);                    }                    loop = false;                }                Thread.currentThread().sleep(50);            }            //展示响应信息            System.out.println(sb.toString());            socket.close();        } catch (IOException | InterruptedException e) {            e.printStackTrace();        }    }}

得到结果:

HTTP/1.1 200 Content-Type: text/html;charset=UTF-8Transfer-Encoding: chunkedDate: Thu, 26 Sep 2019 10:21:08 GMTConnection: close2000(以及Tomcat的index.jsp页面代码)

1.2.2 ServerSocket类

 ServerSocket类和Socket类并不相同。服务器套接字必须时刻待命,它不知道客户端应用程序会在什么时候发起连接。ServerSocket类的构造函数需要指明IP地址和服务器套接字侦听的端口号。

ServerSocket类的其中一个构造函数的签名如下:

public SeverSocket (int port, int backLog, InetAddress bindingAddress);

 

创建了ServerSocket实例后,可以使其等待传入的连接请求,该连接请求会通过服务器套接字侦听的端口上绑定地址传入。这些工作可以通过调用ServerSocket类的accept方法完成。只有当接收到连接请求后,该方法才会返回,其返回值是一个Socket实例。可以使用该Socket对象与客户端应用程序进行字节流的发送/接收。

1.3 应用程序

针对以上知识点,做一个简单的web服务器。HttpServer类相当于一个已经启动了的Tomcat,Request类模拟访问URL,Response类模拟返回消息。

package webDemo;import java.io.*;import java.net.InetAddress;import java.net.ServerSocket;import java.net.Socket;public class HttpServer {    // WEB_ROOT静态资源存放目录    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 server = new HttpServer();        server.await();    }    private void await() {        ServerSocket serverSocket = null;        int port = 8081;        try {            serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));        } catch (IOException e) {            e.printStackTrace();            System.exit(1);        }        while (!shutdown) {            Socket socket;            InputStream input;            FileOutputStream output;            try {                socket = serverSocket.accept();                input = socket.getInputStream();                output = (FileOutputStream) socket.getOutputStream();                // 创建请求的对象和参数                Request request = new Request(input);                request.parse();                // 创建响应对象                Response response = new Response(output);                response.setRequest(request);                response.sendStaticResource();                // 关闭Socket                socket.close();                // 如果URL是shutdown命令                shutdown = request.getUri().equals(SHUTDOWN_COMMAND);            } catch (Exception e) {                e.getStackTrace();                continue;            }        }    }}
package webDemo;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;    }    /**     *  从InputStream对象中读取整个字节流     */    public void parse() {        StringBuffer request = new StringBuffer(2048);        int i;        byte[] buffer = new byte[2048];        try {            i = input.read(buffer);        } catch (IOException e) {            e.getStackTrace();            i = -1;        }        for (int j = 0; j < i; j++) {            request.append((char) buffer[j]);        }        System.out.println("request == " + request.toString());        uri = parseUri(request.toString());    }    /**     * GET /index.html HTTP/1.1     * 该方法在请求行中搜索第一个和第二个空格,从而找出URI     * @param requestString     * @return     */    private String parseUri(String requestString) {        int index1;        int index2 = 0;        index1 = requestString.indexOf(' ');        if (index1 != -1) {            index2 = requestString.indexOf(' ', index1 + 1);        }        if (index2 > index1) {            return requestString.substring(index1 + 1, index2);        }        return null;    }}
package webDemo;import sun.misc.BASE64Decoder;import sun.misc.BASE64Encoder;import java.io.*;/*    HTTP Response = Status-Line        *( (general - header | response-header | entity-header) CRLF)        CRLF        [ message-body ]        Status-Line - HTTP-Version SP Status-Code SP Reason-Phrase CRLF */public class Response {    Request request;    OutputStream output;    public Response(OutputStream output) {        this.output = output;    }    public void setRequest(Request request) {        this.request = request;    }    /**     * 发送静态资源     * @throws IOException     */    public void sendStaticResource() throws IOException {        try {            File file = new File(HttpServer.WEB_ROOT, request.getUri());//目录+文件名            if (file.exists()) {                BufferedReader reader = new BufferedReader(new FileReader(file));                StringBuffer sb = new StringBuffer();                String line;                while ((line = reader.readLine()) != null) {                    sb.append(line).append("\r\n");                }                StringBuffer result = new StringBuffer();                result.append("HTTP/1.1 200 ok \r\n");                result.append("Content-Language:zh-CN \r\n");                // charset=UTF-8 解决中文乱码问题//                result.append("Content-Type:text/html;image/gif;charset=UTF-8 \r\n");                result.append("multipart/x-mixed-replace; boundary=myboundary");                result.append("Content-Length:" + file.length() + "\r\n");                result.append("\r\n" + sb.toString());                output.write(result.toString().getBytes());                output.flush();                output.close();            } 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" +                        "

File Not Found

"; output.write(errorMessage.getBytes()); } } catch (Exception e) { System.out.println("----" + e.toString()); } } private void covertImag(String line) { BASE64Decoder decoder = new BASE64Decoder(); try { byte[] b = decoder.decodeBuffer(line); for (int i = 0; i < b.length; i++) { if (b[i] < 0) { b[i] += 256; } } output.write(b); output.flush(); output.close(); } catch (IOException e) { System.out.println(e.toString()); } }}

 index.html页面的代码:

            Welcome to BrainySoftware                        
Welcome to BrainySoftware.

该html页面中包含一个图片,但是我的代码无法显示代码,暂时没有找到解决办法,留着坑以后填。如果有大神知道如何处理,非常感激能教我。

posted on
2019-09-28 19:47  阅读(
...) 评论(
...) 收藏

转载于:https://www.cnblogs.com/tzzt01/p/11596114.html

你可能感兴趣的文章
SqlServer之Convert 函数应用格式化日期(转)
查看>>
软件测试领域中的10个生存和发展技巧
查看>>
Camera前后摄像头同时预览
查看>>
HDU 1856
查看>>
课堂作业01--架构师的职责
查看>>
iOS计算富文本(NSMutableAttributedString)高度
查看>>
2017/09/15 ( 框架2)
查看>>
Centos下源码安装git
查看>>
gulp-rev-append md5版本号
查看>>
IO流之File类
查看>>
sql 基础语句
查看>>
CF717A Festival Organization(第一类斯特林数,斐波那契数列)
查看>>
oracle直接读写ms sqlserver数据库(二)配置透明网关
查看>>
控件发布:div2dropdownlist(div模拟dropdownlist控件)
查看>>
Oracle composite index column ordering
查看>>
ActiveReports 报表控件官方中文入门教程 (3)-如何选择页面报表和区域报表
查看>>
kaggle竞赛
查看>>
区块链入门教程
查看>>
域 搭建OU 组织单元
查看>>
npm常用命令
查看>>