动手实现一个简单的CS模型(仿照tomcat)

动手实现一个简单的CS模型(仿照tomcat)

Tomcat 服务器是Web 应用服务器,浏览器则可看作web应用客户端。客户端与服务端是通过点对点的socket通信,在http协议规范下进行的。

http协议分为请求部分和响应部分

请求部分格式

请求行 : 请求方法 请求路径 http协议及版本
请求头 :  键值对
请求空行 
请求体 : get方法无,post方法有

例子:
GET / HTTP/1.1
Host: www.baidu.com
...

响应部分格式

响应行    http协议及版本 状态码 响应提示信息
响应头    键值对
响应空行
响应体    服务器返回的数据
 HTTP/1.1 200 ok
 server: Apache-Coyote/1.1
 ...
 
 网页数据

基于socket和请求,模拟浏览器请求数据

public class TestClient {

    public static void main(String[] args) {

        Socket s = null;
        OutputStream os = null;
        InputStream is = null;

        try {
            
            s = new Socket("www.baidu.com",80);
            os = s.getOutputStream();
            is = s.getInputStream();

            os.write("GET / HTTP/1.1\n".getBytes());
            os.write("HOST:www.baidu.com\n".getBytes());
            os.write("\n".getBytes());

            int i = is.read();
            while(i!=-1){
                System.out.print((char)i);
                i = is.read();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(s!=null){
                try {
                    s.close();
                } catch (IOException e) { }
            }

            if(os!=null){
                try {
                    os.close();
                } catch (IOException e) { }
            }

            if(is!=null){
                try {
                    is.close();
                } catch (IOException e) { }
            }
        }


    }
}

基于socket和响应,模拟服务器响应客户端

package com.lovehot.learn.BS;

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

/**
 * @author 州牧
 * @description 服务器响应请求
 * @since 2022-03-26 19:26
 */
public class TestServer {
    public static void main(String[] args) {
        ServerSocket ss = null;
        Socket s = null;
        OutputStream os = null;

        try {
            
            ss = new ServerSocket(8080);
            while(true) {

                /*监听8080端口*/
                s = ss.accept();
                
                os = s.getOutputStream();
                
                os.write("HTTP/1.1 200 ok\n".getBytes());
                os.write("Content-Type: text/html;charset=utf-8\n".getBytes());
                os.write("Server: zhoumu/2020\n".getBytes());
                os.write("\n\n".getBytes());
                StringBuffer buffer = new StringBuffer();
                buffer.append("<html>");
                buffer.append("<head>");
                buffer.append("<title>");
                buffer.append("百度一下,你就知道");
                buffer.append("</title>");
                buffer.append("</head>");
                buffer.append("<body>");
                buffer.append("度娘");
                buffer.append("</body>");
                buffer.append("</html>");
                os.write(buffer.toString().getBytes());

                /*将缓冲区内容也返回*/
                os.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(ss != null){
                try {
                    ss.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if(s != null){
                try {
                    s.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if(os != null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


    }
}

完整版本

tomcat中有分为静态请求和动态请求,在MyServer简单的分离了动静态的请求,静态请求直接返回静态资源,动态请求则会由Servlet流程负责返回动态数据,为了简便起见这里未链接数据库而实现业务。

MyServlet中定义servlet的基本行为,MyServer被请求,解析请求和分离请求。

MyServlet

package com.lovehot.learn.mycat;

import java.io.InputStream;
import java.io.OutputStream;

public interface MyServlet {

        //初始化
        void init();
        //服务
        void Service(InputStream is, OutputStream ops);
        //销毁
        void destroy();

}

MyServletImpl

package com.lovehot.learn.mycat;

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

/**
 * @author 州牧
 * @description
 * @since 2022-03-26 22:11
 */
public class MyServletImpl implements MyServlet{

    @Override
    public void init() {
        System.out.println("初始化servlet生存环境");
    }

    @Override
    public void Service(InputStream is, OutputStream os) {
        try {
            os.write("已经获取到前端传来的数据,servlet进行处理".getBytes());
            os.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void destroy() {
        System.out.println("生命周期结束,销毁");
    }
}

MyServer

package com.lovehot.learn.mycat;

import com.lovehot.learn.version2.Servlet;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 州牧
 * @description 服务器响应请求
 * @since 2022-03-26 19:26
 */
public class MyServer {
    //获取到项目下的WebContent目录
    public static final String WEB=System.getProperty("user.dir") + "\\" + "Web";
    // 代表客户端要请求资源的路径
    public  static String url = "";

    public static Map<String,String> map = new HashMap<>();

    //加载配置信息
    static {
        map.put("aa","MyServletImpl");
    }

    public static void main(String[] args) {


        ServerSocket ss = null;
        Socket s = null;
        OutputStream os = null;
        InputStream is = null;


        try {
            ss = new ServerSocket(8080);
            /*监听端口*/
            s = ss.accept();

            os = s.getOutputStream();
            is = s.getInputStream();

            //获取url
            parseUrl(is);

            if(url.indexOf(".")!=-1){
                //静态资源
                sendStaticResource(os);
            }else{
                //动态资源
                sendDynamicResource(os,is);
            }


        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(ss != null){
                try {
                    ss.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if(s != null){
                try {
                    s.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if(os != null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if(is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


    }

    private static void sendDynamicResource(OutputStream os, InputStream is) {
        try {
            os.write("HTTP/1.1 200 OK\n".getBytes());
            os.write("Server:apache\n".getBytes());
            os.write("Content-Type:text/html;charset=utf-8\n".getBytes());
            os.write("\n".getBytes());

            if(map.containsKey(url)){

                String value = map.get(url);
			
                Class clazz = Class.forName(value);
                Servlet servlet = (Servlet)clazz.newInstance();

                servlet.init();
                servlet.Service(is, os);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private static void sendStaticResource(OutputStream os) {

        byte[] bytes = new byte[1024*2];

        FileInputStream fis = null;

        File file = new File(WEB+url);

        try{
            if(file.exists()){
                os.write("HTTP/1.1 200 OK\n".getBytes());
                os.write("Server:apache-Coyote/1.1\n".getBytes());
                os.write("Content-Type:text/html;charset=utf-8\n".getBytes());
                os.write("\n".getBytes());

                fis = new FileInputStream(file);

                int i = fis.read(bytes);
                while(i!=-1){
                    os.write(bytes,0,i);
                    i = fis.read(bytes);
                }
            }else {
                //如果文件不存在,客户端响应文件不存在消息
                os.write("HTTP/1.1 404 not found\n".getBytes());
                os.write("Server:apache-Coyote/1.1\n".getBytes());
                os.write("Content-Type:text/html;charset=utf-8\n".getBytes());
                os.write("\n".getBytes());
                String errorMessage = "file not found";
                os.write(errorMessage.getBytes());
                os.flush();
            }
        }catch (Exception e){
            throw new RuntimeException("发送资源出错");
        }finally {
            if(fis!=null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    private static void parseUrl(InputStream is) {

        
        StringBuffer content = new StringBuffer(1024*3);

        byte[] buffer = new byte[1024*3];

        try {
            int i = is.read(buffer);
            for (int j = 0; j <i; j++) {
                content.append((char) buffer[j]);
            }



            int index1,index2;
            index1 =content.indexOf(" ");
            index2 = content.indexOf(" ",index1+1);

            /*"GET /demo.html HTTP/1.1*/
            url = content.substring(index1+1,index2);

        } catch (Exception e) {
            e.printStackTrace();
        }


    }


}

通过:https://www.bilibili.com/video/BV1AW41117Cu?spm_id_from=333.337.search-card.all.click 学习

完整版本源码:

链接:https://pan.baidu.com/s/12sCER8_sVPjJbwC7RkVG3A

提取码:java

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值