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

本文介绍了一个仿照Tomcat的简单CS模型实现,包括客户端请求数据和服务器响应客户端的过程。此外,还介绍了如何分离静态和动态请求,并通过MyServlet处理动态请求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

动手实现一个简单的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

在Qt中创建一个简单的计算器,你可以按照以下步骤进行: 1. **环境准备**: - 首先确保你已经安装了Qt Creator和对应的版本的Qt库,可以访问Qt官方网站下载并安装。 2. **创建新项目**: - 在Qt Creator中选择"File" > "New File or Project",然后选择"Qt Widgets Application",给项目起个名字,比如"CalculatorApp"。 3. **设计界面**: - 使用Qt Designer打开"*.ui"文件,添加基本的窗口元素,如按钮、标签等,并布局成计算器的标准界面,包括数字键、运算符按钮以及结果显示区域。 4. **编码实现**: - 在生成的`mainwindow.h`和`mainwindow.cpp`文件中,连接UI元素到相应的槽函数。 - 使用信号槽机制,例如设置每个数字和运算符按钮点击事件,当点击时触发槽函数,更新显示结果或执行计算操作。 5. **处理计算逻辑**: - 在`mainwindow.cpp`中,为每个槽函数编对应的逻辑。例如,当用户输入一个数字时,将其添加到当前的操作数列表;当用户按下运算符时,清空显示结果,开始新的计算过程。 6. **错误处理和清理**: - 考虑处理非法输入,比如除数为零的情况,确保在执行计算前检查输入的合法性。 7. **测试应用**: - 在Qt Creator中运行应用程序,通过模拟实际操作验证功能是否正常。 ```cpp // 示例代码片段: void MainWindow::on_pushButton_plus_clicked() { double num1 = ui->lineEdit_number1->text().toDouble(); double num2 = ui->lineEdit_number2->text().toDouble(); ui->lineEdit_result->setText(QString::number(num1 + num2)); } // 类似地为其他运算符按钮和清除按钮编槽函数 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值