手动实现一个简易的web服务器

本文介绍了如何手动实现一个简单的Web服务器。首先,通过启动Socket服务并循环接收浏览器请求。然后,解析请求,检查资源是否存在。如果资源存在,服务器将响应发送回客户端;如果不存在,则返回404错误。文章详细讲解了Server、Request和Response类的设计与实现,并提供了测试步骤,包括创建WebContent文件夹来存储HTML资源。

整体思路

  • 启动Socket服务,循环的接收浏览器请求
  • 接收到请求之后,将流中的数据取出
  • 判断目标资源是否存在,若不存在,返回404
  • 若存在,将目标资源通过输出流响应给客户端

实现这个服务器应有的类及其功能

  • Server:用于开启Socket服务
  • Request:用于封装请求,处理请求相关的业务
  • Response:封装响应,处理响应相关业务
  • Test:测试类

具体代码实现

Server类

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

public class MyHttpServer {
    //端口
    private int port=8080;
    //ip为服务器的ip
    //接收请求的方法
    public void receiving(){
        try {
            //创建Socket服务
            ServerSocket serverSocket=new ServerSocket(port);
            //循环接收请求
            while (true){
                //循环接收请求,获取 Socket 对象,获取到了连接对象
                Socket socket=serverSocket.accept();
                //获取连接对象的输入流
                InputStream inputStream=socket.getInputStream();
                //创建Request对象
                MyHttpRequest request=new MyHttpRequest(inputStream);
                //解析请求
                request.parse();
                //开始响应,创建Response
                //获取连接对象的输出流
                OutputStream outputStream=socket.getOutputStream();
                MyHttpResponse response=new MyHttpResponse(outputStream);
                //根据获取的uri进行响应
                response.sendRedirect(request.getUri());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Request类

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

public class MyHttpRequest {
    //接收连接对象的输入流并解析
    private InputStream inputStream;
    //目标资源的路径
    private  String uri;

    public MyHttpRequest(InputStream inputStream) {
        this.inputStream = inputStream;
    }
    //解析输入流
    public void parse(){
        try {
            byte[] bytes=new byte[1024];
            //把输入流中的东西读到数组中
            inputStream.read(bytes);
            //封装成字符串
            /*
            GET /a.html HTTP/1.1
            Host: localhost:8080
            Connection: keep-alive
            sec-ch-ua: "Chromium";v="106", "Microsoft Edge";v="106", "Not;A=Brand";v="99"
            sec-ch-ua-mobile: ?0
            sec-ch-ua-platform: "Windows"
            Upgrade-Insecure-Requests: 1
            User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36 Edg/106.0.1370.47
            Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*`............
            */
            String request=new String(bytes);
            //获取请求的目标资源路径,如http://localhost:8080/a.html中的a.html
            parseUri(request);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void parseUri(String request){
        int index1,index2;
        index1=request.indexOf(' ');
        index2=request.indexOf(' ',index1+1);
        this.uri=request.substring(index1+1,index2);
        System.out.println(uri);
    }
    //返回uri
    public String getUri(){
        return this.uri;
    }
}

Response类

import java.io.*;
import java.lang.reflect.Field;

//根据解析得到的uri判断请求的资源是否存在,存在做出相应,不存在404
public class MyHttpResponse {
    private OutputStream outputStream;

    public MyHttpResponse(OutputStream outputStream) {
        this.outputStream = outputStream;
    }
    public void sendRedirect(String uri){
        //判断uri是否存在,是否再目标工程中
        //不存在返回404
        //存在,直接返回目标资源

        //得到请求资源的整体路径
        String path=System.getProperty("user.dir")+"/WebContent"+ uri;
        //根据路径创建一个file对象
        File file=new File(path);
        //判断文件是否存在
        if(file.exists()){
            try {
                //存在返回目标资源数据,根据目标资源路径,获取资源
                FileInputStream fileInputStream=new FileInputStream(file);
                byte[] bytes=new byte[(int)file.length()];
                fileInputStream.read(bytes);
                //得到资源内容
                String result =new String(bytes);
                //返回浏览器能显示的格式
                String response=getResponseMessage("200",result);
                this.outputStream.write(response.getBytes());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }else {
            try {
                //不存在返回404,getResponseMessage返回浏览器能显示的格式
                String error=getResponseMessage("404","404 File Not Found!");
                this.outputStream.write(error.getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    //返回浏览器能显示的格式
    public String getResponseMessage(String code,String message){
        return "HTTP/1.1"+code+"\r\n"
                +"Content-type:text/html\r\n"
                +"Content-Length:"+message.length()
                +"\r\n"
                +"\r\n"
                +message;
    }
}

测试

建立一个WebContent文件夹,用于存放请求的html资源
在这里插入图片描述
测试类

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

请求存在的资源时,端口号为8080
在这里插入图片描述
在这里插入图片描述

请求不存在的资源时
在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值