计算机网络—HTTP协议:深入解析与应用实践

                                        🎬慕斯主页修仙—别有洞天

                                       ♈️今日夜电波:ヒステリックナイトガール

                                                           1:03━━━━━━️💟──────── 5:06
                                                                🔄   ◀️   ⏸   ▶️    ☰  

                                 💗关注👍点赞🙌收藏您的每一次鼓励都是对我莫大的支持😍


 

目录

什么是HTTP协议?

URL

什么是URL?

urlencode和urldecode

HTTP请求和响应的格式

HTTP请求格式

HTTP的方法

HTTP响应格式

HTTP的状态码

HTTP常见Header

请求头(Request Header)

响应头(Request Header)

设计一个简单的HTTP服务器

解析HTTP请求格式

根据上面解析出来的数据创建服务器

一些细节的知识

重定向

Cookie


什么是HTTP协议?

        HTTP协议,全称Hypertext Transfer Protocol,即超文本传输协议,是互联网上应用最为广泛的一种网络传输协议。它定义了客户端(如浏览器)与服务器之间的通信规范,以实现对各种资源(如HTML页面、图像、音频、视频等)的传输和访问。HTTP协议基于请求响应模式,客户端向服务器发送请求消息,请求消息中包含请求方法、URL、协议版本以及请求头等信息。服务器接收到请求消息后,根据请求消息的URL和相应的处理逻辑,生成服务器响应消息,并将其发送给客户端。响应消息中包含协议版本、状态码、响应头和响应体等信息。客户端接收到响应消息之后,会根据自身的处理方式进行处理,例如如果是网页,客户端会解析响应体中的HTML代码并渲染出网页。

URL

什么是URL?

        平时我们俗称的 "网址" 其实就是说的 URL,如下图所示:

        需要注意的是:http默认绑定的端口号是80、https默认绑定的端口号是443。而其中的服务器地址实际上就是我们的ip地址,如下的地址是相同的:我们可以指定端口来访问。如果不指定则会使用默认的端口。

http://www.qq.com:80      ==        61.241.54.232:80

        实际上我们看到服务器网址后带的文件路径我们这个时候就很清楚了,这不就是我们在Linux中常用的文件目录结构吗?实际上也的确是这样的,我们通过URL请求服务,可以带上指定的路径,将该路径下的资源文件返回给用户。

        对于带层次的文件路径来说,第一个 / 表示为web根目录,第二个 / 开始表示为路径分隔符。 // 通常被当作单个斜杠来处理。

        ?表示为查询字符串的开头,参数和数值使用键值对的形式(KV结构)进行表示,多个键值对之间使用与号(&)分隔。例如,?param1=value1&param2=value2。

        # 表示为片段标识的开头,后面跟着资源的特定部分或ID。它主要用于客户端的导航,不会被发送到服务器。

urlencode和urldecode

        像 / ? : 等这样的字符, 已经被url当做特殊意义理解了. 因此这些字符不能随意出现.比如, 某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义.

        转义的规则如下:将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY格式。如下:

HTTP请求和响应的格式

        下面是对上述图解的解释:

        HTTP请求和响应的格式在Web开发中非常重要,它们定义了客户端(通常是浏览器)和服务器之间如何通信。以下是关于HTTP请求和响应格式的简要概述:(需要注意的是:他们通常使用\r\n进行分隔)

HTTP请求格式

        HTTP请求通常由以下部分组成:

  1. 请求行(Request Line):包含HTTP方法(如GET、POST等)、请求的URL和HTTP版本(如HTTP/1.1)。
GET /example.html HTTP/1.1

  1. 请求头部(Request Headers):包含关于请求的各种元数据,如浏览器类型、请求来源、内容类型等。
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
...
  1. 空行:请求头部之后是一个空行,用于分隔请求头部和请求体。
  2. 请求体(Request Body):对于某些HTTP方法(如POST或PUT),请求体包含发送到服务器的数据。这通常用于提交表单或上传文件。

        下面对于其中的细节进行详细的叙述:

HTTP的方法

        我们比较常用的就是GET和POST方法,下面详细介绍:

        GET方法主要用于请求获取指定的资源。当客户端(如Web浏览器)使用GET方法向服务器发起请求时,它会将请求的参数附加到URL的末尾,并以明文形式发送。这些参数通常是以键值对的形式存在,并且在URL中可见。由于GET请求的参数直接暴露在URL中,因此它不适合处理敏感数据,如密码或金额等。此外,GET请求只产生一个TCP数据包,且浏览器会缓存GET请求的结果,这意味着如果用户回退或刷新页面,浏览器不会再次发送请求,而是从缓存中获取结果。GET请求还具有幂等性,即多次执行相同的GET请求,服务器返回的结果都是一样的。

        与GET方法不同,POST方法主要用于向指定资源提交数据进行处理,如提交表单或上传文件。当使用POST方法时,提交的数据会放置在HTTP请求的主体中,而不是附加到URL上。这意味着POST请求可以提交大量的数据,且数据在传输过程中不会明文显示,从而提高了安全性。然而,由于POST请求不会缓存,每次用户回退或刷新页面时,浏览器都需要重新发送请求。此外,POST请求是非幂等的,即多次执行相同的POST请求可能会导致不同的结果。

HTTP响应格式

HTTP响应同样由几个部分组成:

  1. 状态行(Status Line):包含HTTP版本、状态码和状态消息。状态码用于表示请求的处理结果,如200表示成功,404表示未找到资源等。
HTTP/1.1 200 OK

  1. 响应头部(Response Headers):包含关于响应的各种元数据,如内容类型、内容长度、服务器类型等。
Content-Type: text/html; charset=UTF-8
Content-Length: 12345
Server: Apache/2.4.46 (Unix)
...

  1. 空行:响应头部之后同样是一个空行,用于分隔响应头部和响应体。
  2. 响应体(Response Body):这是服务器返回给客户端的实际数据,可以是HTML、JSON、XML等任何格式。

        请注意,不是所有的HTTP请求都包含请求体(例如GET请求),同样也不是所有的HTTP响应都包含响应体(例如某些只包含状态信息的响应)。

        下面对于其中的细节进行详细的叙述:

HTTP的状态码

        常见的状态码:

200 OK:表示请求已成功处理,并返回了所请求的资源。这是最常见的成功状态码。

302Redirect表示临时重定向。当服务器返回302状态码时,意味着请求的资源已被临时移动到另一个位置,并且服务器会提供一个新的URL地址,以便客户端能够重新发送请求并获取所需资源。

403 Forbidden:表示服务器拒绝了客户端的请求,因为客户端没有访问权限。这可能是因为客户端未经授权或身份验证失败,或者服务器设置了访问限制。

404 Not Found:表示请求的资源在服务器上不存在。当客户端发起请求时,如果服务器无法找到与请求URL对应的资源,通常会返回这个状态码。

500 Internal Server Error:表示服务器在处理请求时遇到了内部错误。这可能是由于服务器上的代码或配置错误导致的。

504 Bad Gateway :表示网关超时(Gateway Timeout),它是一种服务器端错误响应状态码。当客户端(如浏览器)向服务器发送请求时,如果服务器在一定时间内无法从上游服务器(例如应用程序服务器、数据库服务器)获取到响应,就会返回504错误码给客户端。

HTTP常见Header

请求头(Request Header)
  1. Host:指定目标服务器的主机名或IP地址。
  2. Accept:定义客户端能够接受来自服务器的媒体类型,如application/json, text/html等。这允许服务器发送满足客户端需求的资源。
  3. User-Agent:标识发出请求的Web浏览器或客户端应用程序,使服务器能够根据客户端定制其响应。
  4. Content-Type:标识请求主体中内容的媒体类型,帮助服务器成功解释和处理有效负载。
  5. Cache-Control:指定请求或响应的缓存策略,如max-age、no-cache、no-store等。
  6. 自定义请求头
    • X-Forwarded-Host:在HTTP代理或负载均衡器后面使用。
    • X-Forwarded-For:用于记录客户端的IP地址,特别在使用代理服务器时。
    • X-Requested-With:用于指示请求的类型,如XMLHttpRequest。
    • X-Csrf-Token:用于防止跨站请求伪造攻击。
    • X-Content-Type-Options:用于指示浏览器是否应该自动处理响应体的MIME类型,如nosniff。
    • X-XSS-Protection:用于启用浏览器内置的跨站脚本攻击防护机制。

响应头(Request Header)
  1. Content-Type:这个字段指明了响应主体的媒体类型,即客户端可以如何解析响应的内容。例如,对于HTML页面,该字段的值通常是text/html;对于JSON数据,值则是application/json。
  2. Content-Length:这个字段表示响应主体的长度,以字节为单位。这有助于客户端正确读取整个响应内容。
  3. Date:这个字段表示响应生成的日期和时间,格式为RFC 7231规定的日期时间格式。
  4. Cache-Control:这个字段用于指定缓存策略,控制响应内容在客户端和中间缓存中的缓存行为。例如,no-cache表示每次都需要向服务器验证缓存的内容是否仍然有效;max-age则指定了缓存内容的有效期。
  5. Expires:这个字段用于指定缓存内容的过期时间。与Cache-Control的max-age相比,Expires使用了一个绝对的时间戳来表示过期时间。
  6. ETag:这个字段用于标识响应内容的一个版本,如果内容未发生变化,服务器可以在后续的请求中通过比较ETag来避免发送相同的内容。
  7. Last-Modified:这个字段表示资源最后一次被修改的日期和时间,有助于客户端判断是否需要重新获取资源。
  8. Set-Cookie:这个字段用于设置HTTP cookie,用于会话管理、用户身份验证等目的。
  9. Location搭配3XX状态码使用,指定重定向的目标URL。
  10. Server:这个字段包含了处理请求的服务器软件的名称和版本。
  11. Connection:这个字段用于控制网络连接的行为,例如是否保持连接(keep-alive)或关闭连接。
  12. WWW-Authenticate:当服务器需要客户端提供身份验证信息时,这个字段会被包含在401 Unauthorized响应中,以指示客户端如何进行身份验证。

        下面我们以浏览器作为客户端,向我们自行编写的一个小程序进行访问,看看是否如我们所叙述的一样:

        该程序仅仅是将报文给打印出来,并没有做什么特殊的处理,可以看到正如我们上面所说的,结构层次是相同的,由于没有带正文所以在空行后的正文内容是空的。

        那如果我们想要给客户端返回信息呢?当然也是同上面所叙述的一样,以响应的格式按照HTTP协议的要求给他返回对应的报文,如下,我们按照规则返回一个简单的字符串“hello world!”

             //返回响应过程std::string text="Hello world!";std::string response_line="HTTP/1.0 200 OK\r\n";std::string response_header="Content-Length: ";response_header+=std::to_string(text.size());response_header+="\r\n";std::string blank_line="\r\n";std::string response=response_line;response+=response_header;response+=blank_line;response+=text;send(sockfd,response.c_str(),response.size(),0);

        效果如下:

        需要特别注意的是:网页必须指明编码格式,也就是Content-Type。否则就会出现乱码。通常根据文件的后缀来区别。比如:如果我们放回的是html格式则按照Content-Type对照表返回text/html,png则是image/png。

设计一个简单的HTTP服务器

解析HTTP请求格式

        按照要求我们创建一个Deserialize函数用于解析和处理通过HTTP发送过来的报文,最主要的就是sep=\r\n这个分隔符,根据他我们可以将请求行到Header全部解析,最后根据空行我们可以得到后面的请求正文。创建一个Parse函数用于解析请求方法、URL、http_version,最后分析URL,获得文件路径、要打开的文件类型。

class HttpRequest
{
public:void Deserialize(std::string req){while (true){std::size_t pos = req.find(sep);if (pos == std::string::npos)break;std::string tmp = req.substr(0, pos);if (tmp.empty())break;req_header.push_back(tmp);req.erase(0, pos + sep.size());}text = req;}void Parse(){std::stringstream ss(req_header[0]);ss >> method >> url >> http_version;file_path = wwwroot;if (url == "/" || url == "/index.html"){file_path += "/";file_path += homepage; //./wwwroot/index.html}else{file_path += url;}auto pos = file_path.rfind(".");if (pos == std::string::npos)suffix = ".html";elsesuffix = file_path.substr(pos);}public:std::vector<std::string> req_header;std::string text;// 解析之后的结果std::string method;std::string url;std::string http_version;std::string file_path; // ./wwwroot/a/b/c.html 2.pngstd::string suffix;
};

根据上面解析出来的数据创建服务器

        这里我们复用了之前实现的socket和日志接口,在初始化的时候仅仅需要传入端口即可,同时我们先自定义仅有两种类型的文件“html”和“png”。这两个分别是给Header中的Content-Type 用的。

        这个服务器使用简易的多线程来实现多人链接,调用pthread_create的函数ThreadRun会使用pthread_deatch来让线程无需等待。一些线程的细节不多叙述啦~

        最主要的还是其中对于http协议的处理函数HandlerHttp。他会读取建立了tcp链接的http协议发来的报文,接着按照报文进行解析,按照我们制定的要求返回响应过程。具体的响应报文下面仅仅给出一些例子:

class HttpServerclass ThreadData
{
public:ThreadData(int soc, HttpServer *s): sockfd(soc), svr(s){}public:int sockfd;HttpServer *svr;
};class HttpServer
{
public:HttpServer(uint16_t port = defaultport) : port_(port){content_type.insert({".html", "text/html"});content_type.insert({".png", "image/png"});}bool Start(){listensock_.Socket();listensock_.Bind(port_);listensock_.Listen();for (;;){std::string clientip;uint16_t clientport;int sockfd = listensock_.Accept(&clientip, &clientport);lg(Info, "get a new connect, sockfd: %d", sockfd);pthread_t tid;ThreadData *td = new ThreadData(sockfd, this);pthread_create(&tid, nullptr, ThreadRun, td);}}static std::string ReadHtmlContent(const std::string &hemlpath){std::ifstream in(hemlpath, std::ios::binary);if (!in.is_open())return "";//获得文件总大小in.seekg(0, std::ios_base::end);auto len = in.tellg();//回到开头in.seekg(0, std::ios_base::beg);std::string content;content.resize(len);in.read((char*)content.c_str(), content.size());in.close();return content;}std::string SuffixToDesc(const std::string &suffix){auto iter = content_type.find(suffix);if(iter == content_type.end()) return content_type[".html"];else return content_type[suffix];}void HandlerHttp(int sockfd){char buffer[10240];ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);if (n > 0){buffer[n] = 0;std::cout << buffer;HttpRequest req;req.Deserialize(buffer);req.Parse();// 返回响应过程std::string text;bool ok = true;text = ReadHtmlContent(req.file_path);if(text.empty()){ok = false;std::string err_html = wwwroot;err_html += "/";err_html += "err.html";text = ReadHtmlContent(err_html);}std::string response_line;if(ok)response_line = "HTTP/1.0 200 OK\r\n";elseresponse_line = "HTTP/1.0 404 Not Found\r\n";std::string response_header = "Content-Length: ";response_header += std::to_string(text.size());response_header += "\r\n";response_header += "Content-Type: ";response_header += SuffixToDesc(req.suffix);response_header += "\r\n";std::string blank_line = "\r\n";std::string response = response_line;response += response_header;response += blank_line;response += text;send(sockfd, response.c_str(), response.size(), 0);}close(sockfd);}static void *ThreadRun(void *args){pthread_detach(pthread_self());ThreadData *td = static_cast<ThreadData *>(args);td->svr->HandlerHttp(td->sockfd);delete td;return nullptr;}private:Sock listensock_;uint16_t port_;std::unordered_map<std::string, std::string> content_type;
};

        结合HTML我们可以实现如下的效果:

        借用了一位大佬的HTML代码:

        当遇到访问错误的路径时可以合理的处理:

 

一些细节的知识

        在了解完上面的知识后,相信对于http已经有了一定的认识。下面讲讲细节的东西:

重定向

        前面提到有3开头的状态码,这是重定向状态码。这里要详细介绍一下永久重定向和临时重定向的区别:

        永久重定向(HTTP状态码301)表示原URL不应再被使用,而新的URL应替换它。这通常发生在站点更改其URL结构后,以确保旧的链接或书签能够继续有效。这种重定向是永久性的,一旦实施,搜索引擎和其他客户端应更新其索引和缓存,以反映新的URL。

        临时重定向(HTTP状态码302)则意味着请求的资源已被临时移动到其他位置,并且服务器已经提供了新的URL,以便客户端可以重新发送请求。这种重定向是暂时的,可能由于资源暂时不可用或正在进行维护等原因而发生。当资源恢复其原始位置或维护完成后,客户端应继续使用原始URL。

        在搜索引擎优化的角度,永久重定向对于确保网站的排名和流量至关重要,因为它告诉搜索引擎旧的URL已被新的URL永久替代。而临时重定向则不会对搜索引擎的排名产生长期影响,因为搜索引擎知道这只是暂时的变化。

        需要注意的是:上述的重定向都是会搭配header中介绍过的Location搭配3XX状态码使用,指定重定向的目标URL)使用。

        我们要重定向则可以在响应行和header中添加对应的状态码和header和kv结构即可。如下:

            std::string response_line="HTTP/1.0 301 Moved Permanently\r\n";//永久重定向//std::string response_line="HTTP/1.0 302 Found\r\n";//临时重定向std::string response_header = "Location: http://www.qq.com";response_header += "\r\n";

Cookie

        Cookie 是一种在 Web 开发中广泛使用的技术,用于在客户端(通常是用户的浏览器)存储信息。这些信息可以是用户偏好、会话状态或其他任何需要在多次请求和页面加载之间保持的数据。

        以下是关于 Cookie 的详细解释:

1. 基本概念

  • 定义:Cookie 是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器后续向同一服务器发送请求时被携带上,用于实现用户跟踪和会话管理等功能。
  • 作用:通过 Cookie,服务器可以识别特定的用户,并根据之前保存的信息为用户提供个性化的内容或服务。

2. 工作原理

  1. 设置 Cookie:当服务器响应一个 HTTP 请求时,它可以通过在 HTTP 响应头中设置 Set-Cookie 字段来发送一个或多个 Cookie 到客户端。这样客户端就可以使用这些数据,一些操作如:验证身份操作就不用重复的进行了。
  2. 接收和存储 Cookie:浏览器在接收到含有 Set-Cookie 的响应后,会将这些 Cookie 存储在本地。
  3. 发送 Cookie:在后续的 HTTP 请求中,浏览器会自动将之前存储的 Cookie 通过 Cookie 请求头发送到服务器。

3.Cookie的分类

  1. 内存Cookie:也被称为非持久Cookie或会话Cookie。这种Cookie是由浏览器维护并保存在内存中的,因此其存在时间是短暂的。当电脑关机或浏览器关闭后,内存Cookie就会自动消失。
  2. 硬盘Cookie:也被称为持久Cookie。这种Cookie保存在硬盘中,一般是在浏览器的目录下有一个文件单独存放。硬盘Cookie有一个过期时间,除非用户手动删除或者cookie过期,否则cookie不会被删除,其存在时间是长期的。

        如下便是一个网站的例子:

        大致的代码理解:

            std::string response_line="HTTP/1.0 200 OK\r\n";response_header += "Set-Cookie: name=XIXI";response_header += "\r\n";response_header += "Set-Cookie: password=12345678";response_header += "\r\n";

4、Cookie安全问题

        Cookie的安全性是一个重要的议题,因为它们包含了用户的个人信息和会话状态,如果这些信息被恶意利用,可能会导致隐私泄露、身份冒用等安全问题。

5、Session ID

        Session ID是编程中用于跟踪和管理用户会话的重要概念。在Web开发中,会话是指用户与应用程序之间的交互过程,它可以跨越多个页面请求,使应用程序能够在多个页面之间保持状态。例如,当用户登录到网站时,会话可以用来跟踪用户的身份验证状态,以便在用户浏览其他页面时保持其登录状态。

        为了实现会话跟踪,Web应用程序通常会为每个用户分配一个唯一的会话标识符,即Session ID。这个标识符由应用服务器在用户连接时生成,并用于在服务器端存储与特定用户相关的会话信息。Session ID通常可以保存在客户端的Cookie中,或者在URL中作为参数传递。当客户端提交页面请求时,会将这个Session ID发送回服务器,服务器通过解析这个ID来查找和读取对应的会话数据。

        之后访问时,Http 请求都会携带Session id,就可以通过Session id判断是否合法,若合法则可以访问这个资源。虽然仍然可以被窃取,但是一些私人信息还是可以得到保证的。比如:账号密码就不用当心泄露了。

        Session ID的生成过程通常发生在浏览器第一次请求服务器时,服务器会生成一个Session ID并返回给浏览器,这个ID会被保存在浏览器的会话Cookie中。Session在服务器上的默认有效时间通常是30分钟,但可以通过编程设置进行更改。

        然而,值得注意的是,由于Session ID存储在客户端的Cookie中,因此一旦客户端禁用了Cookie,Session也会失效。因此,在使用Session ID进行会话管理时,需要考虑到Cookie可能不可用的情况,并采取适当的备选方案来维护用户的会话状态。

 


                        感谢你耐心的看到这里ღ( ´・ᴗ・` )比心,如有哪里有错误请踢一脚作者o(╥﹏╥)o! 

                                       

                                                                        给个三连再走嘛~  

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Photoshop 2024 中文---专业图像处理软件的又一次飞跃

Photoshop 2024是一款功能强大的图像处理软件&#xff0c;广泛应用于创意设计和图像处理领域。它提供了丰富的绘画和编辑工具&#xff0c;包括画笔、铅笔、颜色替换、混合器画笔等&#xff0c;使用户能够轻松进行图片编辑、合成、校色、抠图等操作&#xff0c;实现各种视觉效果…

如何使用极狐GitLab 启用自动备份功能

本文作者&#xff1a;徐晓伟 GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署极狐GitLab。 本文主要讲述了如何极狐GitLab 自…

利用Node.js实现拉勾网数据爬取

引言 拉勾网作为中国领先的互联网招聘平台&#xff0c;汇集了丰富的职位信息&#xff0c;对于求职者和人力资源专业人士来说是一个宝贵的数据源。通过编写网络爬虫程序&#xff0c;我们可以自动化地收集这些信息&#xff0c;为求职决策和市场研究提供数据支持。Node.js以其非阻…

基于Python的豆瓣电影评分可视化,豆瓣电影评分预测系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

【stm32】I2C通信外设

【stm32】I2C通信外设 概念部分 如果简单应用&#xff0c;选择软件I2C。如果对性能指标要求比较高 选择硬件I2C 有硬件电路自动反转引脚电平&#xff0c;软件只需要写入控制寄存器CR和数据寄存器DR 为了实时监控时序的状态&#xff0c;还要读取状态寄存器SR 写入控制寄存器CR…

nodeJs 实现视频的转换(超详细教程)

前段时间拿到一个视频是4k的&#xff0c;没法播放&#xff0c;于是通过 node.js 和 ffmpeg 实现了视频的转换。在win10 系统下实现。 所需工具 node 16.19 直接安装 ffmpeg-5.1.1-essentials_build 解压后重名 ffmpeg 放到C盘 然后配置下环境变量 Git-2.42.0.2-64-bit 直接…

一键更换ip地址命令的应用方法

在数字化时代&#xff0c;IP地址作为网络设备的标识符&#xff0c;其重要性不言而喻。然而&#xff0c;在某些特定场景下&#xff0c;我们可能需要频繁地更换IP地址&#xff0c;如网络爬虫、隐私保护或测试环境等。这时&#xff0c;一键更换IP地址的命令就显得尤为重要。虎观代…

51单片机实验02- P0口流水灯实验

目录 一、实验的背景和意义 二、实验目的 三、实验步骤 四、实验仪器 五、实验任务及要求 1&#xff0c;从led4开始右移 1&#xff09;思路 ①起始灯 &#xff08;led4&#xff09; ②右移 2&#xff09;效果 3&#xff09;代码☀ 2&#xff0c;从其他小灯并向右依…

美易官方:现在不考虑降息,可能需要进一步加息

美联储密集放鹰&#xff1a;现在不考虑降息&#xff0c;可能需要进一步加息 达拉斯联储主席洛根&#xff08;Lorie Logan&#xff09;周五表示&#xff0c;考虑降息还为时过早&#xff0c;理由是近期通胀数据高企&#xff0c;且有迹象显示&#xff0c;借贷成本对经济的拖累可能…

人脸识别:Arcface--loss+code

之前只接触过传统方法的人脸识别算法&#xff0c;本以为基于深度学习的方法会使用对比损失之类的函数进行训练&#xff0c;但是Arcface算法基于softmax进行了创新&#xff0c;本文未深究其详细的loss公式原理&#xff0c;在大致明白其方向下&#xff0c;运行了代码&#xff0c;…

太阳能光伏储能系统:全周期一站式解决方案

随着全球能源结构的不断变革&#xff0c;清洁能源的重要性日益凸显。太阳能光伏储能系统作为一种高效、环保的能源解决方案&#xff0c;正逐渐成为推动能源转型的关键力量。本文将详细介绍太阳能光伏储能系统的全周期一站式解决方案&#xff0c;以期为读者提供全面、深入的了解…

MacOS - brew 和 brew cask 有什么区别?

brew 是 ruby 的包管理&#xff0c;后来看 yangzhiping 的博客介绍了 brew cask&#xff0c;感觉 cask 是更好的关联关系管理&#xff0c;但是&#xff0c;我后来使用过程中&#xff0c;发现很多软件 brew cask 里没有&#xff0c;但是 brew 里面倒是挺多&#xff01;今天来给说…

SpringBoot(48)-使用 SkyWalking 进行分布式链路追踪

Spring Boot&#xff08;48&#xff09;- 使用 SkyWalking 进行分布式链路追踪 介绍 在分布式系统中&#xff0c;了解各个服务之间的调用关系和性能表现是非常重要的。SkyWalking 是一款开源的分布式系统监控与分析平台&#xff0c;能够帮助我们实现分布式系统的链路追踪、性…

Java流操作解析:深度剖析中间操作、终端操作与并行处理机制

文章目录 一、中间操作1.1 过滤&#xff08;filter&#xff09;1.2 映射&#xff08;map&#xff09;1.3 排序&#xff08;sorted&#xff09;1.4 去重&#xff08;distinct&#xff09; 二、 终端操作2.1 收集&#xff08;collect&#xff09;2.2 计数&#xff08;count&#…

使用 ChatGPT 创建在线课程:一步一步指南与提示模板

原文&#xff1a;Creating Online Courses with ChatGPT 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 谢谢 作为对你支持的感谢&#xff0c;随意定制本书中列出的任何提示&#xff0c;并将其作为你自己的重新销售。是的&#xff0c;对你免费。 它们都结构良好且用…

二叉树算法练习day.2

102.二叉树的层序遍历 链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例 1&#xff1a; 输入&a…

AcWing 312. 乌龟棋(每日一题)

原题链接&#xff1a;312. 乌龟棋 - AcWing题库 小明过生日的时候&#xff0c;爸爸送给他一副乌龟棋当作礼物。 乌龟棋的棋盘只有一行&#xff0c;该行有 N 个格子&#xff0c;每个格子上一个分数&#xff08;非负整数&#xff09;。 棋盘第 1 格是唯一的起点&#xff0c;第…

AI绘画:实例-利用Stable Diffusion ComfyUI实现多图连接:区域化提示词与条件设置

在Stable Diffusion ComfyUI中&#xff0c;有一种高级技巧可以让用户通过细致的区域化提示词来控制图像的不同部分&#xff0c;从而实现多图连接的效果。这种方法允许艺术家在同一画布上展现多个场景&#xff0c;创造出富有层次和故事性的图像。以下是实现这一效果的详细步骤。…

搜索技术 笔记

1.提高搜索精准度&#xff1a;英文输入法下的双引号 2.ctrlF 3 intitle: 限定标题里含这个东西 4. allintitle:限定标题里含几个关键词 allintitle&#xff1a;赵丽颖 知否 5.intext&#xff1a;限定文章内容的关键词 6.李子柒 inurl:cctv 7.site:cctv.com 完整的域名 …

vue2+elementUi的两个el-date-picker日期组件进行联动

vue2elementUi的两个el-date-picker日期组件进行联动 <template><el-form><el-form-item label"起始日期"><el-date-picker v-model"form.startTime" change"startTimeChange" :picker-options"startTimePickerOption…