手写一个WEB应用服务

之前有小伙伴向我请教一道笔试题:要求写出一个WEB应用服务,不得使用Servlet接口,用Socket实现,可以响应get请求,打印请求信息,并判断请求资源,若不存在,返回404信息,若资源存在,返回该资源,并且可以返回默认的静态页面。

我简单写了一个小Demo,实现了上述功能,在这里分享给大家。

思路

主线程启动Socket服务,循环接收客户端请求,接收到请求后,将流中的数据取出拼接成字符串,在控制台打印。响应时判断请求资源是否存在,若存在,将资源通过输出流响应给客户端,若资源不存在,将404错误信息通过输出流响应给客户端,同时指定一个静态页面作为默认返回。

创建4个类

MyHttpServer:定义Socket服务,循环接收请求。

MyHttpRequest:自定义请求对象,解析请求。

MyHttpResponse:自定义响应对象,根据请求做出响应。

Test:测试类,主线程中启动Socket服务。

代码

package com.southwind.server;

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 MyHttpServer {
    public static String WebContent = System.getProperty("user.dir") + File.separator + "WebContent";
    private int port = 8080;
    private boolean isShutdown = false;
    public void receiving() {
        ServerSocket serverSocket = null;

        try {
            serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
        } catch (IOException ex) {
            ex.printStackTrace();
            System.exit(1);
        }

        // 接收请求
        while (!isShutdown) {
            Socket socket = null;
            InputStream is = null;
            OutputStream os = null;
            try {
                //获取连接
                socket = serverSocket.accept();
                is = socket.getInputStream();
                os = socket.getOutputStream();
                //解析请求
                MyHttpRequest request = new MyHttpRequest(is);
                request.parse();
                //响应
                MyHttpResponse response = new MyHttpResponse(os);
                response.sendStaticResource(request);

            } catch (Exception ex) {
                ex.printStackTrace();
            }finally {
                // 关闭
                try {
                    socket.close();
                    is.close();
                    os.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}
package com.southwind.server;

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

public class MyHttpRequest {

    private InputStream input;
    private String uri;

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

    public void parse() {
        StringBuffer requestStr = new StringBuffer(2048);
        int i;
        byte[] buffer = new byte[2048];

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

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

        System.out.println(requestStr.toString());
        uri = parseUri(requestStr.toString());
    }

    private String parseUri(String requestStr) {
        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;
    }
}
package com.southwind.server;

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

public class MyHttpResponse {
    private OutputStream output;

    public MyHttpResponse(OutputStream output) {
        this.output = output;
    }

    public void sendStaticResource(MyHttpRequest request) throws IOException {
        byte[] bytes = new byte[1024];
        FileInputStream fis = null;
        String filePath = request.getUri() == null ? "" : request.getUri().trim();
        if (filePath.equals("/")) {
            filePath = "/index.html";
        }

        try {
            String result = null;
            File file = new File(MyHttpServer.WebContent, filePath);
            byte[] fileByte = new byte[(int) file.length()];

            if (file.exists()) {
                fis = new FileInputStream(file);
                fis.read(fileByte);
                fis.close();

                result = new String(fileByte);
                result = warpMessage("200", result);
                output.write(result.getBytes());

            } else {
                String errorMessage = warpMessage("404", "404 File Not Found!  The requested URL /404/ was not found on this server. ");
                output.write(errorMessage.getBytes());
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private String warpMessage(String statusCode, String message) {
        return "HTTP/1.1 " + statusCode + "\r\n" + "Content-Type: text/html\r\n" + "Content-Length: " + message.length()
                + "\r\n" + "\r\n" + message;
    }
}
package com.southwind.server;

public class Test {
    public static void main(String[] args) {
        System.out.println("Server startup successfully");
        MyHttpServer server = new MyHttpServer();
        server.receiving();
    }
}

源码:

github

https://github.com/southwind9801/MyWebServer.git

原文发布于微信公众号 - Java大联盟(javaunion)

原文发表时间:2018-08-01

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏项勇

笔记 33 | Android通信之Thread类实现多线程

21550
来自专栏阿杜的世界

Java Web技术经验总结(六)

这个函数中的关键是几个If...else...语句,通过判断指定的类是否存在,来决定是否添加对应的messageConverter(在4.0之后应该可以使用@C...

7820
来自专栏智能大石头

关于自定义控件设计时如何把属性写入aspx中的研究(上)

如何通过继承GridView来修改在设计时绑定数据源时自动生成的ASP.Net代码? 具体情况是这样的,ObjectDataSource绑定到实体类,Grid...

24380
来自专栏移动端开发

Android学习--持久化(一) 文件存储

持久化之   文件存储        这里把Android持久化全都整理一下,这一篇文章先简单的说一下文件的存储,通过下面一个简单的Demo,理解一下这个文件存...

211100
来自专栏Android知识点总结

4-SII--☆Android缓存文件(带有效时长)封装

12120
来自专栏Android机动车

我的图片四级缓存框架

开发App一定涉及到图片加载、图片处理,那就必须会用到三方的图片框架,要么选择自己封装。至于主流的三方图片框架,就不得不说老牌的ImageLoader、如今更流...

15730
来自专栏Zephery

Spring项目路径

Spring源码——WebUtils 个人网站中部署的服务器共有两台,由于是分布式的环境,为了防止有效的针对具体某个服务器出现的问题,需要在网页上加上服务器的I...

37340
来自专栏分布式系统进阶

Kafka集群Metadata管理Kafka源码分析-汇总

可以看到是调用了ReplicaManager.maybeUpdateMetadataCache方法, 里面又会调用到MetadataCache.updateCa...

28520
来自专栏java 成神之路

Spring 加载、解析applicationContext.xml 流程

52860
来自专栏游戏杂谈

Unity的Input输入

Unity中的输入管理器由Input类进行操控。官方文档地址:https://docs.unity3d.com/ScriptReference/Input.ht...

28720

扫码关注云+社区

领取腾讯云代金券