手写一个简单的web服务器(B/S架构)

涉及Web服务器的相关技术

IO流、Socket网络编程、HTTP协议、文件、多线程(同时处理多个浏览器的请求)、List集合

1 web应用服务器运行原理:

  • 连接过程:Web服务器与其浏览器之间建立的连接,判定两者之间是否连接成功;若用户可以找到并打开虚拟文件套接字,说明Web服务器与其浏览器之间成功建立了连接。

  • 请求过程:Web浏览器利用socket文件向其服务器发出各种请求。

  • 获取请求资源的地址

  • 根据是静态资源还是动态资源做出相应的处理

  • 响应过程:在请求过程中发出的请求通过使用HTTP协议传输到Web服务器,然后执行任务处理。

  • 关闭连接:响应过程完成后,Web服务器与其浏览器断开连接的过程。

2 代码展示

(1)Main类

package com.weh;
import com.weh.httpserver.MyHttpServer;
public class Main {
//    开启多线程
    public static void main(String[] args) {
        new Thread(new MyHttpServer()).start();
    }
}

(2)MyHttpServer类

package com.weh.httpserver;
import com.weh.response.MyResponse;
import com.weh.request.MyRequest;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/*
* 1.通过Runnable接口的实现类,来开启线程
* 2.创建并开启服务器
* 3.实现服务端与客户端进行连接通信
* */
public class MyHttpServer implements Runnable{
    public static final int port = 8080;    //服务器端口号
    public static final String WEB_ROOT=System.getProperty("user.dir")+
            File.separator+ "webapps";      //服务器的当前文件目录路径

    @Override
    public void run() {
        ServerSocket serverSocket=null;
        Socket socket;
        InputStream input=null;
        OutputStream output=null;
        try {
            System.out.println("Web服务器已开启");
            serverSocket = new ServerSocket(port); //传入端口号并创建服务器

        } catch (Exception e) {
            System.exit(0);
        }
        //服务端与客户端浏览器进行通信
        while(true){
            try {
                socket=serverSocket.accept();//请求
                input=socket.getInputStream();//获取客户端发过来信息
                output=socket.getOutputStream();
                MyRequest request=new MyRequest(input); //数据处理
                request.parse();
                MyResponse response=new MyResponse(output);
                response.setMyRequest(request);
                response.sendStaticResource();//发送
            } catch (Exception e) {
                e.printStackTrace();
                continue;
            }finally {
                //    释放资源
                release(input,output);
            }
        }
    }
//    释放资源
    public void release(InputStream inputStream,OutputStream outputStream){
        try {
            if(inputStream != null) {
                inputStream.close();
            }
            if(outputStream != null){
                outputStream.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

(3)MyRequest类

package com.weh.request;

import java.io.InputStream;
/*
 * 自定义MyRequest类
 * 1.主要处理客户端发过来的信息进行处理并输出
 * 2.获取客户端切换到哪个文件的名称
 * */
public class MyRequest {
    private InputStream input;
    private String uri;

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

//    输出客户端发过来的信息
    public void parse(){
        StringBuffer request=new StringBuffer(2048);
        int len;
        byte[] buffer=new byte[2048];
        try {
            len=input.read(buffer);
        } catch (Exception e) {
            len=-1;
        }
        for(int j=0;j<len;j++){
            request.append((char)buffer[j]);
        }
        System.out.print(request.toString());
        parseUri(request.toString());
    }

//  获取切换后的文件名
    public void parseUri(String srt){
        int index1,index2;
        index1=srt.indexOf(" ");
        if(index1!=-1){
            index2=srt.indexOf(" ",index1+1);
            if(index2>index1){
                setUri(srt.substring(index1+1,index2));
            }
        }
    }

    public void setUri(String uri) {
        this.uri = uri;
    }

    public String getUri(){
        return this.uri;
    }
}

(4)MyResponse类

package com.weh.response;
import com.weh.httpserver.MyHttpServer;
import com.weh.request.MyRequest;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;

/*
 * 自定义MyResponse类
 * 1.向Socket的输出流中写请求给浏览器作出响应的结果
 * 2.获取当前目录下的所有文件并创建文件类型的数组
 * 3.数据的读取及转发
 * */
public class MyResponse {
    private static final int BUFFER_SIZE=1024;
    MyRequest request;
    OutputStream output;
    FileInputStream fis=null;
    PrintWriter printWriter =null;
    public MyResponse(OutputStream output){
        this.output=output;
    }
    public void setMyRequest(MyRequest request){
        this.request=request;
    }
    public void sendStaticResource()throws IOException{
        byte[] bytes=new byte[BUFFER_SIZE];
        try {
            printWriter = new PrintWriter(output); //创建缓冲字符输出流
            File file=new File(MyHttpServer.WEB_ROOT+request.getUri());
            if(file.exists()){  //判断文件目录是否存在
                //向Socket的输出流中写请求给浏览器作出响应的结果
                printWriter.println("HTTP/1.1 200 OK");
                printWriter.println("Content-Type:text/html;charset=UTF-8");
                printWriter.println();
//                判断文件是否为普通文件
                if(file.isFile()){
                    fis=new FileInputStream(file.getPath());    //创建文件字节输入流
                    fis.read(bytes);  //读取直接流
                    printWriter.write(new String(bytes));
//                判断文件是否为文件目录
                }else if(file.isDirectory()){
                    List<File> list= Arrays.asList(new File(file.getPath()).listFiles());//获取当前目录下的所有文件并创建文件类型的数组
                    for(File filename : list){//数组遍历
                      if(filename.getName().indexOf(".htm")>0) {//判断是否含有.htm的字符的文件
                          printWriter.write("<li>");
                          printWriter.write("<a style='text-decoration:blink;' href='" +
                                  "./" + filename.getName() + "'>"
                                  + filename.getName() + "</a>");
                          printWriter.write("</li>");
                      }
                    }
                }
//           若该文件不存在,则输出信息 File Not Found
            }else{
                printWriter.println("HTTP/1.1 404 File Not Found");
                printWriter.println("Content-Type:text/html;charset=UTF-8");
                printWriter.println("Content-Length:23");
                printWriter.println();
                printWriter.write("<h1>File Not Found</h1>");
            }
            printWriter.flush();//不返回任何值,只用于刷新流
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(printWriter!=null){
                printWriter.close();
            }
            if(output!=null){
                output.close();
            }
            if(fis!=null){
                fis.close();
            }
        }
    }
}

3项目的结构设计

在这里插入图片描述

4 效果展示

在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT_WEH_coder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值