第1章 手写WebServer

news2024/12/28 4:39:08

1.1 Web原理

1.1.1 Web概述

        Web是指互联网上的万维网(World Wide Web),是一个由超文本、超链接和多媒体内容组成的信息空间。Web的基础技术是HTTP协议、URL、HTML、CSS和JavaScript等。Web被广泛应用于信息检索、在线购物、社交媒体、在线游戏、在线视频和音乐等领域。

        Web的好处如下:

  • 全球范围的信息共享:Web使得人们可以通过互联网共享信息、知识和文化。用户可以在全球范围内获取和分享信息,这为人们提供了前所未有的便利。
  • 便利的在线服务:Web使得人们可以轻松地访问在线服务,如电子邮件、社交媒体、在线银行、在线购物和在线学习等。这些服务可以大大提高人们的生产力和便利性。
  • 多媒体内容的呈现:Web使得多媒体内容,如图像、视频和音频,可以轻松地在互联网上呈现和传播。这些内容不仅丰富了用户的体验,也为教育和娱乐等领域提供了新的机会。
  • 云计算和Web应用程序:Web应用程序可以在云计算环境中运行,使得用户可以使用网络浏览器轻松访问和使用这些应用程序。这些应用程序包括在线办公套件、在线协作工具、电子商务网站等。

        Web作为一种重要的信息和娱乐渠道,它可以为用户提供全球信息共享、便利的在线服务、多媒体内容的呈现、云计算和Web应用程序等。

1.1.2 Web工作原理

        Web的工作原理是基于客户端-服务器模型(B/S)的。简单来说,Web由Web服务器、Web客户端和通信协议组成。

1、Web服务器

        Web服务器是一个可以接收客户端请求的软件程序。它运行在一个计算机上,一般是指提供Web服务的主机,可以在这个主机上存储Web页面、图像和其他资源。当Web服务器接收到一个客户端请求后,它会发送一个HTTP响应,包括被请求资源的内容和元数据。

2、Web客户端

        Web客户端是通过浏览器访问Web的用户设备,如电脑、手机等。当用户在浏览器中输入URL时,浏览器会发送一个HTTP请求到Web服务器。Web服务器接收到请求后,会查找请求的资源并将响应返回给浏览器,浏览器会将响应显示在用户的屏幕上。

3、HTTP协议

        Web的通信是基于HTTP协议进行的。HTTP是一种客户端-服务器协议,用于传输超文本文档(HTML、XML、图片等)。它定义了浏览器和Web服务器之间的请求和响应交互方式。当浏览器发送HTTP请求时,请求会包含HTTP方法(GET、POST、PUT等)、请求的URL和HTTP头部信息。Web服务器会解析HTTP请求并生成HTTP响应。HTTP响应会包括状态码、HTTP头部信息和响应正文。状态码表示请求是否成功,HTTP头部信息包含了响应的元数据,响应正文则包含了请求的数据。

4、HTML

        HTML是用于创建Web页面的标记语言。HTML标签描述了文本和其他内容在Web页面上的显示方式。浏览器可以读取HTML文件,并将其转换成可视化的Web页面。

        因此,Web的工作原理是基于HTTP协议和客户端-服务器模型的。Web服务器接收HTTP请求,查找并生成响应,并将其发送回浏览器。浏览器读取响应并将其转换成可视化的Web页面。

1.2 手写WebServer

1.2.1 手写WebServer的意义

        手写WebServer对学习编程有很大的意义:有助于深入理解Web的工作原理和HTTP协议的细节,可以提高对计算机网络和操作系统的理解,并增强编程和软件开发的能力。

        1、理解Web工作原理:通过编写代码,实现客户端和服务端的信息交互,从而理解Web的工作原理和HTTP通信协议,掌握Web应用程序和网络通信的底层原理。

        2、提高编程能力:手写WebServer需要掌握网络编程、操作系统和Web开发等多种技能,有利于更好地理解软件开发的基本原理和技术,并掌握高效编程的方法和技巧。

        3、加强调试能力:手写WebServer需要不断地测试和调试,从而加强调试能力,有助于更好地掌握软件调试的方法和技巧,从而提高开发效率和代码质量。

        4、培养创新意识:手写WebServer需要不断地思考和创新,可以培养创新意识,并学会在开发过程中不断提高自己的能力和水平。

        懂源码的程序员才是真正的程序员。要想原生手写WebServer就需要从深入学习HTTP协议开始。

1.2.2 HTTP协议

        HTTP(Hypertext Transfer Protocol)协议是一种应用层协议,用于在Web浏览器和Web服务器之间传输数据。HTTP协议是Web的基础技术之一,它定义了客户端(如Web浏览器)和服务器之间的通信规则,使得Web可以实现信息的交互和共享。

        HTTP协议的设计是为了解决在Web上传输数据的问题。在早期的Web中,各种应用程序使用不同的通信协议,导致Web上的信息交流困难,信息共享也受到了限制。HTTP协议的出现解决了这些问题,使得Web的发展更加迅速和广泛。

        HTTP协议的优势如下:

  • 简单易用:HTTP协议的设计非常简单,易于理解和实现。这使得开发人员可以更快地开发Web应用程序,并且更容易调试和维护。
  • 可扩展性:HTTP协议的设计具有良好的可扩展性。这意味着可以通过添加新的功能和特性来改进HTTP协议,从而满足不断变化的需求。
  • 无状态:HTTP协议是无状态协议,它不保存任何关于请求或响应的状态信息。这使得Web服务器可以处理大量的请求,并提高了Web应用程序的可伸缩性。
  • 可靠性:HTTP协议的设计非常可靠,可以确保数据在客户端和服务器之间的安全传输。HTTP协议还支持数据压缩、数据加密等技术,提高了数据传输的效率和安全性。

        HTTP协议是一种简单易用、可扩展、无状态和可靠的应用层协议,它使得Web应用程序可以高效地传输和共享数据,从而推动了Web的发展和应用。

1.2.3 HTTP协议工作原理

        HTTP协议是一个客户端-服务器协议,它的工作原理可以分为以下几个步骤:

        1、建立连接:客户端向服务器发送一个连接请求,请求连接到服务器。客户端可以通过TCP/IP协议或TLS/SSL协议建立连接。

        2、发送请求:客户端向服务器发送HTTP请求,请求包括请求方法、请求头、请求体等信息。常见的请求方法包括GET、POST、PUT、DELETE等。

        3、处理请求:服务器接收到HTTP请求后,根据请求的方法和URL等信息进行处理。服务器可以返回HTTP响应,包括响应状态码、响应头和响应体等信息。

        4、发送响应:服务器向客户端发送HTTP响应,响应包括响应状态码、响应头、响应体等信息。

        5、关闭连接:一旦HTTP响应发送完毕,服务器和客户端都可以选择关闭连接。关闭连接可以释放网络资源,提高性能和安全性。

        在HTTP协议中,客户端和服务器之间的通信是通过HTTP报文进行的。HTTP报文分为请求报文和响应报文,分别用于客户端向服务器发送请求和服务器向客户端发送响应。HTTP报文包括起始行、头部字段和消息体等部分,它们用于传输数据和控制信息。

        总之,HTTP协议是一个客户端-服务器协议,它通过HTTP报文来传输数据和控制信息。HTTP协议的工作原理是建立连接、发送请求、处理请求、发送响应和关闭连接等步骤。

1.2.4 WebServer的处理步骤

        Java WebServer的大致处理步骤如下:

        1、创建一个ServerSocket对象:ServerSocket对象用于监听指定的端口,并接受客户端的请求。

        2、等待客户端连接:通过调用ServerSocket的accept()方法,等待客户端的连接请求。当有客户端连接时,accept()方法返回一个Socket对象,用于和客户端进行通信。

        3、解析HTTP请求:从Socket对象中读取客户端的请求数据,并将其解析为HTTP请求。HTTP请求由请求行、请求头和请求体组成。

        4、处理HTTP请求:根据HTTP请求中的方法、路径和参数等信息,处理客户端的请求,并生成HTTP响应。HTTP响应由状态行、响应头和响应体组成。

        5、发送HTTP响应:将HTTP响应发送回客户端,并关闭Socket连接。

        实现一个WebServer涉及到很多细节,例如解析HTTP请求、处理GET和POST请求、生成HTTP响应等。

1.3 接收HTTP请求

1.3.1 HTTP请求结构

        HTTP请求报文由三个部分组成:请求行、请求头和请求体。查看一个简单的HTTP GET请求的示例:

GET /hello.txt HTTP/1.1

Host: example.com

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

1、请求行

        请求行是HTTP请求报文的第一行,包括HTTP方法、请求URI和HTTP版本。请求行的格式如下:

METHOD URI HTTP_VERSION

        其中:METHOD为HTTP方法,通常为GET、POST、PUT、DELETE等;URI为请求资源的路径,可以包含查询参数;HTTP_VERSION为HTTP协议版本,通常为HTTP/1.1或HTTP/2。

        上个示例中,请求行包含了HTTP方法GET、请求路径/hello.txt和HTTP版本号HTTP/1.1。

2、请求头

        请求头紧随请求行之后,以一或多个以冒号分隔的键值对的形式提供附加信息。每个键值对为一行,键和值之间用冒号和空格分隔。请求头包含了客户端发送请求时的各种信息,如Accept、User-Agent、Host等。

        上个示例中,请求头包含了Host、User-Agent和Accept三个键值对。Host指定了服务器的域名或IP地址,User-Agent指定了浏览器的类型和版本,Accept指定了浏览器能够接受的响应格式。

3、请求体

        请求体是HTTP请求报文的可选部分,通常在使用POST或PUT方法提交表单数据时出现。请求体包含了客户端发送到服务器的实际数据,如表单字段、文件内容等。

        上个示例中,GET请求不包含请求消息体,以空行作为结束标识。

        下面是一个HTTP POST请求报文的示例:

POST /login HTTP/1.1

Host: example.com

Content-Type: application/x-www-form-urlencoded

Content-Length: 25

username=john&password=doe

        这个示例中,请求行为POST /login HTTP/1.1,表示使用POST方法向/login路径提交请求。请求头包括了Host、Content-Type和Content-Length三个键值对。请求体为username=john&password=doe,表示提交了用户名和密码两个表单字段的值。注意请求头和请求体之间有一个空行。其中Content-Length的长度25就是请求体中数据“username=john&password=doe”的字节数量。

        关于编码:请求行和请求头都是 ISO8859-1编码,不能直接使用中文,中文需要进行编码处理。

        HTTP协议的详细内容可以参考HTTP协议官方文档 RFC2616标准:RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1。

1.3.2 接收HTTP请求

        使用Java编程实现接收浏览器的HTTP请求,可以使用Java的Socket和ServerSocket类来实现一个简单的HTTP服务器。具体步骤如下:

        1、创建ServerSocket对象,并指定监听的端口号8088。

ServerSocket serverSocket = new ServerSocket(8088);

        2、使用accept()方法等待客户端的连接请求,并获取客户端的Socket对象。

Socket clientSocket = serverSocket.accept();

        3、从客户端Socket对象中获取输入流,先尝试一个简单方式读取HTTP请求报文(请求消息),读取代码示意如下:

InputStream in = clientSocket.getInputStream();
int b;
while ((b=in.read())!=-1){
    	System.out.print((char) b);
}
in.close();

1.3.3 接收HTTP请求实现

        编写服务端代码,实现接收HTTP请求,完整案例代码如下

public class ServerBootApplication {
    private ServerSocket serverSocket;

    public void start(){
        try {
            //创建ServerSocket对象,并指定监听的端口号8088。
            serverSocket = new ServerSocket(8088);
            //使用accept()方法等待客户端的连接请求,并获取客户端的Socket对象
            Socket clientSocket = serverSocket.accept();
            //从客户端Socket对象中获取输入流,读取HTTP请求报文(请求消息)。
            InputStream in = clientSocket.getInputStream();
            int b;
            while ((b=in.read())!=-1){
                System.out.println((char) b);
            }
            in.close();
            //关闭客户端连接
            clientSocket.close();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        //创建ServerBoot对象
        ServerBootApplication1 application = new ServerBootApplication1();
        //启动服务器
        application.start();
    }
}

        打开浏览器向 http://localhost:8088 发起请求,在开发工具控制台上输出如下信息:

        这些信息是一个浏览器发送的一个HTTP GET请求,不同浏览器信息略有区别。

        这个案例存在问题,客户浏览器会一直卡住“转圈圈”,原因是浏览器没有主动断开网络,只有断开网络时候,服务器端才能收到“-1”程序才能继续执行,否则就会在in.read()位置进行阻塞等待,客户端效果就是“转圈圈”。

        如何解决这个问题呢?要分析一下HTTP GET请求消息结构:

        GET请求消息每个行结束符号为“\r\n”,最后发送了空行“\r\n”为结束,我们改进程行读取到空行就结束读取,让循环结束,代码改进如下:

//从客户端Socket对象中获取输入流,读取HTTP请求报文(请求消息)。
InputStream in = clientSocket.getInputStream();
StringBuilder builder= new StringBuilder();
//   前一个字符  当前字符
char previous = 0, current = 0;
int b;
while ((b=in.read())!=-1){
    //将读取的字节存储到当前字符, 由于请求头采用了ISO8859-1编码,
    // 所以可以讲字节直接转化为字符类型
    current = (char) b;
    //如果发现了 前一个字符是 \r 当前字符是 \n 就读取到了行末尾
    if (previous == '\r' && current == '\n'){
        //如果这一行是空行就结束处理了
        if (builder.toString().isEmpty()){
            break;
        }
        //输出这一行数据当前一行数据并且清空builder,为下次缓存数据做准备
        System.out.println(builder);
        builder.delete(0, builder.length());
    }else if (current != '\r' && current != '\n'){
        //当前的不是 \r \n 就是一行中的字符
        builder.append(current);
    }
    //最后将当前的字符作为下次的前一个字符
    previous = current;
}
in.close();

        这段代码从客户端Socket对象的输入流中读取HTTP请求报文(请求消息)。该代码使用一个StringBuilder对象来存储读取到的数据,并使用一个while循环遍历输入流中的字节。

        在while循环中,代码将当前字节转换为字符类型并存储到变量current中,同时检查前一个字符是否是回车符(\r)并且当前字符是否是换行符(\n),如果是,就表示读取到了一行的末尾,将该行数据输出并清空StringBuilder对象。

        如果当前字符不是回车符或换行符,那么就是一行中的字符,将该字符添加到StringBuilder对象中。

        在处理完一行数据后,将当前字符作为下次循环的前一个字符;最后,关闭输入流。

        需要注意的是,请求报文采用了ISO8859-1编码,因此可以将字节直接转换为字符类型。

        案例的完整代码如下:

public class ServerBootApplication {
    private ServerSocket serverSocket;

    public void start(){
        try {
            //创建ServerSocket对象,并指定监听的端口号8088。
            serverSocket = new ServerSocket(8088);
            //使用accept()方法等待客户端的连接请求,并获取客户端的Socket对象
            Socket clientSocket = serverSocket.accept();
            //从客户端Socket对象中获取输入流,读取HTTP请求报文(请求消息)。
            InputStream in = clientSocket.getInputStream();
            StringBuilder builder= new StringBuilder();
            //   前一个字符  当前字符
            char previous = 0, current = 0;
            int b;
            while ((b=in.read())!=-1){
                //将读取的字节存储到当前字符, 由于请求头采用了ISO8859-1编码,
                // 所以可以讲字节直接转化为字符类型
                current = (char) b;
                //如果发现了 前一个字符是 \r 当前字符是 \n 就读取到了行末尾
                if (previous == '\r' && current == '\n'){
                    //如果这一行是空行就结束处理了
                    if (builder.toString().isEmpty()){
                        break;
                    }
                    //输出这一行数据当前一行数据并且清空builder,为下次缓存数据做准备
                    System.out.println(builder);
                    builder.delete(0, builder.length());
                }else if (current != '\r' && current != '\n'){
                    //当前的不是 \r \n 就是一行中的字符
                    builder.append(current);
                }
                //最后将当前的字符作为下次的前一个字符
                previous = current;
            }
            in.close();

            //关闭客户端连接
            clientSocket.close();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        //创建ServerBoot对象
        ServerBootApplication application = new ServerBootApplication();
        //启动服务器
        application.start();
    }
}

        服务器端可以正常显示浏览器的请求信息,并且服务端程序可以正常结束:

1.4 发送HTTP响应

1.4.1 HTTP响应

        在上一节案例中虽然服务器端结束了,但是客户端端得到了一个不正常的结果:

        其原因是:服务器没有向浏览器发送任何响应消息,浏览器没有收到任何信息。解决办法就是在服务端程序,向浏览器发送响应消息。

1.4.2 响应消息结构

        要能正确发送响应消息就必须了解完整的响应消息结构。HTTP响应消息由三部分组成:状态行、响应头和响应正文。

1、状态行

        状态行由HTTP协议版本、状态码和状态描述组成,通常格式如下:

HTTP/1.1 200 OK

        其中,HTTP/1.1表示HTTP协议的版本,200表示状态码,OK是状态描述。

Content-Type: text/html

Content-Length: 1234

Date: Fri, 25 Feb 2023 10:00:00 GMT

        响应正文是服务器返回的实际数据,可以是HTML网页、图片、文本等等。响应正文的格式和内容取决于服务器返回的数据类型和内容。

        完整的HTTP响应消息结构如下:

HTTP/1.1 200 OK

Content-Type: text/html; charset=utf-8

Content-Length: 1234

Date: Fri, 25 Feb 2023 10:00:00 GMT

<html>

<head>

<title>Example</title>

</head>

<body>

<p>This is an example.</p>

</body>

</html>

        其中响应头Content-Type: text/html; charset=utf-8 用于说明,响应正文中的内容类型,这是text/html表示,响应正文中是一个html网页,charset=utf-8表示响应正文中的网页采用UTF-8编码。

        响应头Content-Length: 1234,用于说明响应正文中内容长度,单位是字节数量。

        需要注意的是,HTTP响应消息中的每个部分都使用特定的分隔符进行分割。状态行和响应头之间使用一个空行进行分割,响应头和响应正文之间也使用一个空行进行分割。服务器端需要按照HTTP协议规定的格式构造响应消息,客户端收到响应消息后也需要按照HTTP协议规定的方式解析响应消息。

1.4.3 向浏览器发送HTTP响应

        在Java中向浏览器发送HTTP响应需要借助Java中的Socket和OutputStream等类。以下是一个简单的Java程序示例,可以向浏览器发送一段HTML内容的HTTP响应:

OutputStream out = clientSocket.getOutputStream();
//一个简单的网页内容
String html = "<html>\n" +
        "<head>\n" +
        "<title>Example</title>\n" +
        "</head>\n" +
        "<body>\n" +
        "<p>Hello World!</p>\n" +
        "</body>\n" +
        "</html>";
byte[] body = html.getBytes(StandardCharsets.UTF_8);
out.write("HTTP/1.1 200 OK".getBytes(StandardCharsets.ISO_8859_1));
out.write('\r');
out.write('\n');
out.write("Content-Type: text/html; charset=utf-8"
	.getBytes(StandardCharsets.ISO_8859_1));
out.write('\r');
out.write('\n');
out.write(("Content-Length: "+body.length)
	.getBytes(StandardCharsets.ISO_8859_1));
out.write('\r');
out.write('\n');
out.write('\r'); //空行
out.write('\n');
out.write(body);
//关闭客户端连接
out.close();

        这段代码用于向客户端发送HTTP响应。具体来说,它先构造了一个简单的HTML网页,然后将HTML内容转换成UTF-8编码的字节数组,将HTTP响应头和响应体分别写入到客户端的输出流中。

        HTTP响应的第一行为状态行,这里写入了“HTTP/1.1 200 OK”,表示HTTP版本为1.1,状态码为200,状态码200表示请求成功。接着写入了响应头信息,包括“Content-Type”表示响应体类型为HTML文本,“charset=utf-8”表示响应体采用的字符集为UTF-8,“Content-Length”表示响应体长度为body的字节数组长度。之后写入一个空行,表示响应头和响应体的分隔符,最后将响应体内容写入到输出流中。

        最后,关闭客户端的输出流,表示该响应已经发送完毕,可以断开与客户端的连接。

        完整案例:

package com.obj.boot;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

public class ServerBootApplication {
    private ServerSocket serverSocket;

    public void start(){
        try {
            //创建ServerSocket对象,并指定监听的端口号8088。
            serverSocket = new ServerSocket(8088);
            //使用accept()方法等待客户端的连接请求,并获取客户端的Socket对象
            Socket clientSocket = serverSocket.accept();
            //从客户端Socket对象中获取输入流,读取HTTP请求报文(请求消息)。
            InputStream in = clientSocket.getInputStream();
            StringBuilder builder= new StringBuilder();
            //   前一个字符  当前字符
            char previous = 0, current = 0;
            int b;
            while ((b=in.read())!=-1){
                //将读取的字节存储到当前字符, 由于请求头采用了ISO8859-1编码,
                // 所以可以讲字节直接转化为字符类型
                current = (char) b;
                //如果发现了 前一个字符是 \r 当前字符是 \n 就读取到了行末尾
                if (previous == '\r' && current == '\n'){
                    //如果这一行是空行就结束处理了
                    if (builder.toString().isEmpty()){
                        break;
                    }
                    //输出这一行数据当前一行数据并且清空builder,为下次缓存数据做准备
                    System.out.println(builder);
                    builder.delete(0, builder.length());
                }else if (current != '\r' && current != '\n'){
                    //当前的不是 \r \n 就是一行中的字符
                    builder.append(current);
                }
                //最后将当前的字符作为下次的前一个字符
                previous = current;
            }

            OutputStream out = clientSocket.getOutputStream();
            //一个简单的网页内容
            String html = "<html>\n" +
                    "<head>\n" +
                    "<title>Example</title>\n" +
                    "</head>\n" +
                    "<body>\n" +
                    "<p>Hello World!</p>\n" +
                    "</body>\n" +
                    "</html>";
            byte[] body = html.getBytes(StandardCharsets.UTF_8);
            out.write("HTTP/1.1 200 OK".getBytes(StandardCharsets.ISO_8859_1));
            out.write('\r');
            out.write('\n');
            out.write("Content-Type: text/html; charset=utf-8".getBytes(StandardCharsets.ISO_8859_1));
            out.write('\r');
            out.write('\n');
            out.write(("Content-Length: "+body.length).getBytes(StandardCharsets.ISO_8859_1));
            out.write('\r');
            out.write('\n');
            out.write('\r'); //空行
            out.write('\n');
            out.write(body);
            //关闭客户端连接
            out.close();
            in.close();
            clientSocket.close();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        //创建ServerBoot对象
        ServerBootApplication application = new ServerBootApplication();
        //启动服务器
        application.start();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1634903.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

区块链交易所开发

在当今数字化时代&#xff0c;区块链技术以其独特的去中心化、安全性和透明性&#xff0c;正在逐步改变我们的生活。其中&#xff0c;区块链交易所作为连接区块链技术与广大投资者的桥梁&#xff0c;其开发与发展备受关注。本文将从技术进步与市场需求两个维度&#xff0c;探讨…

【前端】表格合并如何实现?

简言 介绍实现表格合并的一种方法。 表格合并 表格合并操作是一个比较复杂的操作&#xff0c;它主要分为以下步骤&#xff1a; 获取选中区域选择合并显示的单元格实现合并操作。 我们就逐一实现这三步&#xff0c;最后实现一个较完整的合并操作。&#xff08;不考虑边界情…

点成分享 | 温度控制的艺术:TX150系列水浴中的稳定性与均匀性解析

前言 在实验室和工业生产中&#xff0c;温度控制对于确保实验结果的精确性和产品的高质量至关重要&#xff0c;尤其是针对温度敏感的样品和原材料&#xff0c;如蛋白酶等&#xff0c;微小的温度误差都会对实验结果可靠性和生产质量造成影响。而在控温性能中&#xff0c;稳定性…

Pytorch入门实战 P08-YOLOv5里面的C3模块实现

目录 1、YOLOv5骨干网络模型图&#xff1a; 2、C3模块介绍&#xff1a; 3、C3模块的主要代码&#xff1a; 4、完整的code 5、运行结果展示&#xff1a; &#xff08;1&#xff09;使用SGD优化器 &#xff08;2&#xff09;使用Adam优化器 &#x1f368; 本文为&#x1f…

2024年必应bing广告推广开户有什么条件?

必应Bing作为全球领先的搜索引擎之一&#xff0c;其广告平台正为无数企业开辟着新的市场蓝海。如果您正寻求在必应Bing上投放广告&#xff0c;提升品牌影响力和市场份额&#xff0c;那么了解开户条件并找到一位可靠的合作伙伴至关重要。云衔科技&#xff0c;作为数字营销领域的…

Jetson Orin NX L4T35.5.0平台LT6911芯片 调试记录(2)vi discarding frame问题调试

基于上篇调试记录 Jetson Orin NX L4T35.5.0平台LT6911芯片 调试记录(1)MIPI问题调试-CSDN博客 1.前言 当通过gstreamer持续捕获视频设备时,帧数会下降,并且I输入越高,丢失的帧数越多。 当达到4k30hz时,它完全无法使用,系统会在几秒钟的收集后崩溃并重新启动 4k30hz …

使用yolo识别模型对比两张图片并标记不同(2)

上篇文章有漏洞&#xff0c;在这里补充下&#xff0c;比如要识别第二张图相对于第一张图的违建是否拆除了 第一步旋转对其后&#xff0c;图片会有黑色的掩码&#xff0c;如果旋转角度大的话&#xff0c;没识别出来的框可能不是已经拆除了&#xff0c;而是因为黑色掩码遮挡&…

Laravel 框架请求生命周期

Laravel 框架请求的生命周期 目录 请求图示 说明 ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ 请求图示 说明 ① 所有的请求都是经Web 服务器&#xff08;Apache/Nginx&#xff09;配置引导到Laravel 应用的入口public/index.php文件。index.php 加载框架其它部分。 如下图&#xff…

基于FPGA的数字信号处理(3)--什么是浮点数?

科学计数法 你可能不了解「浮点数」&#xff0c;但你一定了解「科学记数法」。 10进制科学记数法把一个数表示成a与10的n次幂相乘的形式&#xff08;1≤|a|<10&#xff0c;a不为分数形式&#xff0c;n为整数&#xff09;&#xff0c;例如&#xff1a; 19970000000000 1.9…

关系(五)利用python绘制连接散点图

关系&#xff08;五&#xff09;利用python绘制连接散点图 连接散点图&#xff08;Connected Scatterplot&#xff09;简介 连接散点图&#xff08;点线图&#xff09;是折线图的一种&#xff0c;与散点图类似。但添加了按数据点出现顺序的连线&#xff0c;以此来表示两个变量…

币圈Cryptosquare论坛

Cryptosquare综合性资讯论坛汇集了币圈新闻、空投信息、社会热点以及与Web3相关的工作信息。让我们一起解锁加密世界的种种可能性&#xff0c;探索Cryptosquare论坛带来的精彩&#xff01; 币圈新闻板块&#xff1a; Cryptosquare论坛的币圈新闻板块是用户获取最新加密货币行业…

vite打包配置

目录 minify默认是esbuild&#xff0c;不能启动下面配置 使用&#xff1a; plugins: [viteMockServe({mockPath: mock})]根目录新建mock/index.ts. 有例子Mock file examples&#xff1a;https://www.npmjs.com/package/vite-plugin-mock-server 开发环境生产环境地址替换。根…

Matlab|含sop的33节点配电网优化

目录 1 主要内容 2 部分代码 3 程序结果 4 下载链接 1 主要内容 程序以IEEE33节点为例&#xff0c;分析含sop的配电网优化&#xff0c;包括sop有功约束、无功约束和容量约束&#xff0c;非线性部分通过转换为旋转锥约束进行编程&#xff0c;并且包括33节点配电网潮流及对应…

python自动化操作docx

使用Python自动化处理Word文档 在日常工作中&#xff0c;我们经常需要处理大量的Word文档&#xff0c;这时自动化脚本就显得尤为重要。本文将介绍如何使用Python中的python-docx库来创建和修改Word文档。 安装python-docx库 在开始之前&#xff0c;确保你已经安装了python-d…

基于JWT实现的Token认证方案

JSON Web Token是什么&#xff1f; JSON Web Token&#xff08;JWT&#xff09;是目前最流行的跨域身份验证解决方案。 JSON Web Token&#xff08;JWT&#xff09;是一个开放标准&#xff08;RFC 7519&#xff09;&#xff0c;它定义了一种紧凑且自包含的方式&#xff0c;用…

电脑文件误删除如何恢复?这5个策略亲测有效!

“求助&#xff01;在电脑上不小心删除了文件还有机会找回来吗&#xff1f;一不小心我就删除了一个重要的工作文件&#xff01;大家快帮帮我吧&#xff01;” 保存在电脑里的文件对电脑用户来说很多都是非常重要的&#xff0c;我们可能生活中、学习上以及工作上都需要使用这些文…

C++学习第七课:控制程序流程的学习和示例详解

C学习第七课&#xff1a;控制程序流程 在C中&#xff0c;控制程序流程是编程逻辑的核心部分&#xff0c;它决定了程序的执行顺序。本课我们将介绍C中的各种控制流程语句&#xff0c;包括条件语句、循环语句以及如何使用它们遍历多维数组和计算斐波那契数列。 控制流程语句 i…

哪个牌子的骨传导耳机好用?盘点五款高热度爆款骨传导耳机推荐!

近年来&#xff0c;骨传导耳机在潮流的推动下销量节节攀升&#xff0c;逐渐成为运动爱好者和音乐迷们的必备装备。但热度增长的同时也带来了一些品质上的忧患&#xff0c;目前市面上的部分产品&#xff0c;存在佩戴不舒适、音质不佳等问题&#xff0c;甚至可能对听力造成潜在损…

VSCode SSH连接远程主机失败,显示Server status check failed - waiting and retrying

vscode ssh连接远程主机突然连接不上了&#xff0c;终端中显示&#xff1a;Server status check failed - waiting and retrying 但是我用Xshell都可以连接成功&#xff0c;所以不是远程主机的问题&#xff0c;问题出在本地vscode&#xff1b; 现象一&#xff1a; 不停地输入…

Python俄罗斯方块

文章目录 游戏实现思路1. 游戏元素的定义2. 游戏区域和状态的定义3. 游戏逻辑的实现4. 游戏界面的绘制5. 游戏事件的处理6. 游戏循环7. 完整实现代码 游戏实现思路 这个游戏的实现思路主要分为以下几个步骤&#xff1a; 1. 游戏元素的定义 Brick类&#xff1a;表示游戏中的砖…