应用层协议Http

Http协议

1.1 什么是http协议

        在进行网络通信时,应用层协议一般都是程序员自己写的,但是有一些大佬其实已经定义出了一些现成的应用层协议,例如:HTTP(超文本传输协议)、FTP(文件传输协议)、SMTP(简单邮件传输协议)、POP3(邮局协议版本3)、IMAP(Internet邮件访问协议)、DNS(域名系统)、SNMP(简单网络管理协议)、DHCP(动态主机配置协议)等等

        HTTP 协议是客户端与服务器之间通信的基础。它规定了客户端(通常是浏览器)和服务器之间交换数据(尤其是超文本)的格式和方式。客户端通过 HTTP 协议向服务器发送请求,服务器收到请求后处理并返回响应。HTTP 协议是一个无连接、无状态的协议,即每次请求都需要建立新的连接,且服务器不会保存客户端的状态信息

1.2 认识Url

URL(Uniform Resource Locator,统一资源定位符)是互联网上标准资源的地址(Address)。它是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。

  • 协议:指定了应用层应该使用哪种协议来访问资源,如http、https、ftp等。
  • 主机名:指定了服务器的域名或IP地址,是资源所在的服务器地址,但是ip地址对于用户来说是不合适的,这里通常是域名例如 www.baidu.com ,当我们通过域名访问服务器时,会自动将域名改为IP地址,所以我们可以认为他们是等价的
  • 端口号:HTTP协议在默认情况下强绑定到TCP的80端口上。这意味着,当浏览器或其他HTTP客户端尝试访问一个Web服务器上的资源时,如果没有指定端口号,它会默认使用80端口来发送请求。服务器在监听80端口时,也会期待接收来自这个端口的HTTP请求,所以url中一般不会包含80端口号。
  • 路径:指定了服务器上资源的路径。
  • 查询字符串:可选部分,位于路径之后,用 ?分隔。它允许向服务器传递额外的信息,如搜索条件、表单数据等。这些信息通常以键值对的形式出现,键值对之间用 & 连接。
  • 片段标识符:可选部分,位于URL的末尾,用 # 分隔。它用于指定资源内部的一个片段(如HTML页面中的一个特定部分)。浏览器会自动滚动到该片段的位置

1.3 urlencode 和 urldecode

        像 / ? : 等这样的字符, 已经被 url 当做特殊意义理解了. 因此这些字符不能随意出现. 比如, 某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义. 转义的规则如下: 将需要转码的字符转为 16 进制,然后从右到左,取 4 位(不足 4 位直接处理),每 2 位 做一位,前面加上%,编码成%XY 格式。

        例如我们搜索关键词c++,此时URL中的字符++就被编码为%2b%2b了

1.4 HTTP 协议请求与响应格式

1.4.1 HTTP请求

HTTP请求包括四部分:

  • 请求行:格式:<请求方法><空格><URL><空格><HTTP版本><\r\n>
  • 请求报头:请求头包含了多个字段,每个字段都是一个键值对,用来描述请求或指定请求的资源、客户端的信息、响应内容应如何接收等。<key>< : 空格><value>
  • 空行:用来标记请求报头结束,方便反序列化
  • 请求正文:如果客户端没有像服务器传输数据的话,请求正文就是空的

注意:

在url中的 / 并不是我们平时见的根目录,他的名字叫web根目录,可以是一台机器的任意一个目录,所有的网站静态资源都保存在这个目录下,当我们访问的url为/时,一般会跳转到该网站的首页

根据http请求的格式,我们就可以将客户端的请求进行反序列化,找到其要访问的资源,在构建应答发送给它。

代码实现思路:

要注意,当我们用浏览器访问我们的机器的资源时,就是构建了一个http请求,浏览器会将请求进行序列化,再将序列化出来的字符串发送给我们,所以我们收到的其实是如上如所示的一条字符串,而我们的工作就是将这个字符串进行反序列化,然后构建应答发送给浏览器

反序列化思路:先粗分再细分

首先我们将收到的序列化字符串先分为请求行,报头、请求正文,报头的话就是多个字符串,我们先把他放在一个字符串数组中。再解析请求行详细分为方法、url、版本的等信息,报头是key-value的格式,我们可以用哈希表来存放

const static std::string base_sep = "\r\n";
const static std::string space_sep = " ";
const static std::string line_sep = ": ";
const static std::string prefixpath = "wwwroot"; // web根目录
const static std::string homepage = "index.html";
const static std::string suffixsep = ".";
const static std::string httpversion = "HTTP/1.0";
const static std::string arg_sep = "?";class HttpRequest
{
private:// 得到一行std::string GetLine(std::string &reqstr){auto pos = reqstr.find(base_sep);if (pos == std::string::npos)return std::string();std::string line = reqstr.substr(0, pos);reqstr.erase(0, line.size() + base_sep.size());return line.empty() ? base_sep : line; // 如果读取到空白行那截取的就是空串,则直接返回空白行就可以}// 解析请求行void ParseReqline(){std::stringstream ss(_req_line);ss >> _method >> _url >> _version;_path += _url;// 添加一个首页if (_path[_path.size() - 1] == '/'){_path += homepage;}auto pos = _url.rfind(suffixsep);if (pos != std::string::npos){_suffix = _path.substr(pos);}else{_suffix = ".default";}}void ParseReqHeader(){for (auto &header : _req_headers){auto pos = header.find(line_sep);if (pos == std::string::npos)continue;std::string k = header.substr(0, pos);std::string v = header.substr(pos + line_sep.size());if (k.empty() || v.empty())continue;_headers_kv.insert(std::make_pair(k, v));}}public:HttpRequest(): _blank_line(base_sep), _path(prefixpath){}~HttpRequest(){}void DeSerialize(std::string &reqstr){// 粗力度反序列_req_line = GetLine(reqstr); // 请求行std::string header;          // 请求报头do{header = GetLine(reqstr);if (header.empty() || header == base_sep)break;_req_headers.push_back(header);} while (true);if (!reqstr.empty()) // 请求正文{_body_text = reqstr;}ParseReqline();ParseReqHeader();}void Print(){std::cout << "----------------------------" << std::endl;std::cout << "###" << _req_line << std::endl;for (auto &header : _req_headers){std::cout << "@@@" << header << std::endl;}std::cout << "***" << _blank_line;std::cout << ">>>" << _body_text << std::endl;std::cout << "Method: " << _method << std::endl;std::cout << "Url: " << _url << std::endl;std::cout << "Version: " << _version << std::endl;for (auto &header_kv : _headers_kv){std::cout << ")))" << header_kv.first << "->" << header_kv.second << std::endl;}}std::string Url(){LOG(DEBUG, "Client Want url %s\n", _url.c_str());return _url;}std::string Path(){LOG(DEBUG, "Client Want path %s\n", _path.c_str());return _path;}std::string Suffix(){return _suffix;}std::string Method(){LOG(DEBUG, "Client request method is %s\n", _method.c_str());return _method;}std::string GetResuestBody(){LOG(DEBUG, "Client request method is %s, args: %s, request path: %s\n",_method.c_str(), _body_text.c_str(), _path.c_str());return _body_text;}private:// 基本HttpRequwst格式std::string _req_line;std::vector<std::string> _req_headers;std::string _blank_line;std::string _body_text;// 更详细的数据std::string _method;std::string _url;std::string _version;std::string _path;std::string _suffix; // 资源后缀std::unordered_map<std::string, std::string> _headers_kv;
};
1.4.2 Http应答

Http应答与请求格式类似也分为4部分:

  • 状态行:格式:<HTTP版本><空格><状态码><空格><状态码描述><\r\n>
  • 相应报头:响应头部与请求头部类似,为响应报文添加了一些附加信息。<key>< : 空格><value>
  • 空行
  • 响应正文:响应正文是服务器返回给客户端的数据部分,包含了服务器对客户端请求的响应内容。响应正文的格式和类型由响应头部中的Content-Type字段指定。

对于相应来说我们只需要序列化,反序列化的工作是由客户端来实现的,将序列化字符串发送给客户端即可

class HttpResponse
{
public:HttpResponse() : _verison(httpversion), _blank_line(base_sep){}void AddCode(int code, const std::string &desc){_status_code = code;_desc = desc;}void AddHeader(const std::string &k, const std::string &v){_headers_kv[k] = v;}void AddBodyText(const std::string &body_text){_resp_body_text = body_text;}std::string Serialize(){// 构建状态行_status_line = _verison + space_sep + std::to_string(_status_code) + space_sep + _desc + base_sep;// 2. 构建应答报头for (auto &header : _headers_kv){std::string header_line = header.first + line_sep + header.second + base_sep;_resp_headers.push_back(header_line);}// 空行在构造函数实现了// 正式序列化std::string responsestr = _status_line;for (auto &line : _resp_headers){responsestr += line;}responsestr += _blank_line;responsestr += _resp_body_text;return responsestr;}private:// httpresponse base 属性std::string _verison;int _status_code;std::string _desc;std::unordered_map<std::string, std::string> _headers_kv;// 基本的httpResponse的格式std::string _status_line;std::vector<std::string> _resp_headers;std::string _blank_line;std::string _resp_body_text;
};

1.5 HTTP 的方法

方法说明支持的HTTP协议版本
GET获取资源1.0 1.1
POST      传输实体1.0 1.1
HEAD获得报文首部1.0 1.1
DELETE删除文件1.0 1.1
OPTIONS询问支持方法1.0
TRACE追踪路径1.0
PUT传输文件1.0 1.1
CONNECT要求用隧道协议连接代理1.0
LINK建立和资源之间的联系1.0
UNLINK断开连接关系1.0

在这些方法中使用最多的是GET方法和POST方法,其中GET方法使用的是最多的。

        

GET

用于请求 URL 指定的资源,POST用于传输实体的主体,通常用于提交表单数据。

两者传输数据的方式不同,GET方法通过url传参,而POST方法则是将参数放到了正文中

1.6 HTTP 的状态码

状态码按照首位数字的不同,可以分为五类:

类别原因短语
1xxInformational(信息性状态码)接收的请求正在处理
2xxSuccess(成功状态码)请求正常处理完毕
3xxRedirection(重定向状态码)需要进行附加操作以完成请求
4xxClient Error(客户端错误状态码)服务器无法处理请求
5xxServer Error(服务器错误状态码)服务器处理请求出错

最常见的状态码, 比如 200(OK), 404(Not Found), 403(Forbidden), 302(Redirect, 重定向), 504(Bad Gateway)

重定向状态码

  • 301永久重定向

        当服务器返回 HTTP 301 状态码时,表示请求的资源已经被永久移动到新的位置。 在这种情况下,服务器会在响应中添加一个 Location 头部,用于指定资源的新位 置。这个 Location 头部包含了新的 URL 地址,浏览器会自动重定向到该地址。

例如,在 HTTP 响应中,可能会看到类似于以下的头部信息:

C++
HTTP/1.1 301 Moved Permanently\r\n
Location: https://www.new-url.com\r\n

        一般用于网站换域名后,自动跳转到新域名, 搜索引擎更新网站链接时使用

  • 302临时重定向

        当服务器返回 HTTP 302 状态码时,表示请求的资源临时被移动到新的位置。 • 同样地,服务器也会在响应中添加一个 Location 头部来指定资源的新位置。浏览 器会暂时使用新的 URL 进行后续的请求,但不会缓存这个重定向。

例如,在 HTTP 响应中,可能会看到类似于以下的头部信息:

C++
HTTP/1.1 302 Found\r\n
Location: https://www.new-url.com\r\n

        一般用于当用户登录成功后跳转到另一个页面

无论是 HTTP 301 还是 HTTP 302 重定向,都需要依赖 Location 选项来指定资 源的新位置。这个 Location 选项是一个标准的 HTTP 响应头部,用于告诉浏览器应该 将请求重定向到哪个新的 URL 地址。

1.7 HTTP 常见 Header

  • Content-Type: 数据类型(text/html 等)
  • Content-Length: Body 的长度
  • Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;
  • User-Agent: 声明用户的操作系统和浏览器版本信息;
  • referer: 当前页面是从哪个页面跳转过来的;
  • Location: 搭配 3xx 状态码使用, 告诉客户端接下来要去哪里访问;
  • Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能;

关于 connection 报头

HTTP 中的 Connection 字段是 HTTP 报文头的一部分,它主要用于控制和管理客户 端与服务器之间的连接状态

核心作用

• 管理持久连接:Connection 字段还用于管理持久连接(也称为长连接)。持久连接允许客户端和服务器在请求/响应完成后不立即关闭 TCP 连接,以便在同一个连接 上发送多个请求和接收多个响应。 持久连接(长连接)

• HTTP/1.1:在 HTTP/1.1 协议中,默认使用持久连接。当客户端和服务器都不明 确指定关闭连接时,连接将保持打开状态,以便后续的请求和响应可以复用同一个连 接。

• HTTP/1.0:在 HTTP/1.0 协议中,默认连接是非持久的。如果希望在 HTTP/1.0 上实现持久连接,需要在请求头中显式设置 Connection: keep-alive。 语法格式

• Connection: keep-alive:表示希望保持连接以复用 TCP 连接。

• Connection: close:表示请求/响应完成后,应该关闭 TCP 连接。

class HttpServer
{
private:std::string GetFile(std::string path){std::ifstream in(path, std::ios::binary);if (!in.is_open())return std::string();in.seekg(0, in.end);int filesize = in.tellg(); // 计算rw偏移量in.seekg(0, in.beg);std::string content;content.resize(filesize);in.read((char *)content.c_str(), filesize);in.close();return content;}public:HttpServer(){_mine_type.insert(std::make_pair(".html", "text/html"));_mine_type.insert(std::make_pair(".jpg", "image/jpeg"));_mine_type.insert(std::make_pair(".png", "image/png"));_mine_type.insert(std::make_pair(".default", "text/html"));_code_to_desc.insert(std::make_pair(100, "Continue"));_code_to_desc.insert(std::make_pair(200, "OK"));_code_to_desc.insert(std::make_pair(201, "Created"));_code_to_desc.insert(std::make_pair(301, "Moved Permanently"));_code_to_desc.insert(std::make_pair(302, "Found"));_code_to_desc.insert(std::make_pair(404, "Not Found"));}std::string HandlerHttpRequest(std::string &reqstr){std::cout << "---------------------------------------" << std::endl;std::cout << reqstr;std::cout << "---------------------------------------" << std::endl;HttpRequest req;req.DeSerialize(reqstr);HttpResponse resp;if (req.Path() == "wwwroot/redir"){// 处理重定向std::string redir_path = "https://www.qq.com";// resp.AddCode(302, _code_to_desc[302]);resp.AddCode(301, _code_to_desc[301]);resp.AddHeader("Location", redir_path);}else{std::string content = GetFile(req.Path()); // 读取目标文件内容if (content.empty())                       // 文件不存在{content = GetFile("wwwroot/404.html");resp.AddCode(404, _code_to_desc[404]);resp.AddHeader("Content-Length", std::to_string(content.size()));resp.AddHeader("Content-Type", _mine_type[".html"]);resp.AddBodyText(content);}else{resp.AddCode(200, _code_to_desc[200]);resp.AddHeader("Content-Length", std::to_string(content.size()));resp.AddHeader("Content-Type", _mine_type[req.Suffix()]);resp.AddBodyText(content);}}std::string respstr = resp.Serialize();return respstr;}
private:std::unordered_map<std::string, std::string> _mine_type;std::unordered_map<int, std::string> _code_to_desc;
};

1.8 通过url调取服务

客户端不仅可以访问我们机器上的静态资源,也可以调取一些服务,例如当我们在百度搜索hello

https://cn.bing.com/search?q=hello&qs=n&form=QBRE&sp=-1&lq=0&pq=hello&sc=10-5&sk=&cvid=3B4149A5C11047A4BD8B5A2487B2D895&ghsh=0&ghacc=0&ghpl=

我们知道cn.bing.com时百度的域名,后面紧跟的/search,是我们要访问的路径,?后面是传递的参数,域名后面的/path既可以是一种资源也可以是一种服务,这里的/search明显是利用后面的参数区调用search服务了

我们实现的时候,可以使用哈希表,利用域名后面的路径来索引我们要执行的服务

using func_t=std::function<HttpResponse(HttpRequest&)>;
class HttpServer
{
private:std::string GetFile(std::string path){std::ifstream in(path, std::ios::binary);if (!in.is_open())return std::string();in.seekg(0, in.end);int filesize = in.tellg(); // 计算rw偏移量in.seekg(0, in.beg);std::string content;content.resize(filesize);in.read((char *)content.c_str(), filesize);in.close();return content;}public:HttpServer(){_mine_type.insert(std::make_pair(".html", "text/html"));_mine_type.insert(std::make_pair(".jpg", "image/jpeg"));_mine_type.insert(std::make_pair(".png", "image/png"));_mine_type.insert(std::make_pair(".default", "text/html"));_code_to_desc.insert(std::make_pair(100, "Continue"));_code_to_desc.insert(std::make_pair(200, "OK"));_code_to_desc.insert(std::make_pair(201, "Created"));_code_to_desc.insert(std::make_pair(301, "Moved Permanently"));_code_to_desc.insert(std::make_pair(302, "Found"));_code_to_desc.insert(std::make_pair(404, "Not Found"));}std::string HandlerHttpRequest(std::string &reqstr){
#ifdef TESTstd::cout << "---------------------------------------" << std::endl;std::cout << reqstr;std::string responsestr = "HTTP/1.1 200 OK\r\n";responsestr += "Content-Type: text/html\r\n";responsestr += "\r\n";responsestr += "<html><h1>hello Linux, hello bite!</h1></html>";return responsestr;
#elsestd::cout << "---------------------------------------" << std::endl;std::cout << reqstr;std::cout << "---------------------------------------" << std::endl;HttpRequest req;req.DeSerialize(reqstr);HttpResponse resp;if (req.Path() == "wwwroot/redir"){// 处理重定向std::string redir_path = "https://www.qq.com";// resp.AddCode(302, _code_to_desc[302]);resp.AddCode(301, _code_to_desc[301]);resp.AddHeader("Location", redir_path);}else if(!req.GetResuestBody().empty()){if(IsServiceExists(req.Path())){_service_list[req.Path()](req);}}else{std::string content = GetFile(req.Path()); // 读取目标文件内容if (content.empty())                       // 文件不存在{content = GetFile("wwwroot/404.html");resp.AddCode(404, _code_to_desc[404]);resp.AddHeader("Content-Length", std::to_string(content.size()));resp.AddHeader("Content-Type", _mine_type[".html"]);resp.AddBodyText(content);}else{resp.AddCode(200, _code_to_desc[200]);resp.AddHeader("Content-Length", std::to_string(content.size()));resp.AddHeader("Content-Type", _mine_type[req.Suffix()]);resp.AddBodyText(content);}}std::string respstr = resp.Serialize();return respstr;
#endif}void InsertService(const std::string& servicename,func_t func){std::string s = prefixpath + servicename;_service_list[s]=func;}bool IsServiceExists(const std::string &servicename){auto iter = _service_list.find(servicename);if(iter == _service_list.end()) return false;else return true;}
private:std::unordered_map<std::string, std::string> _mine_type;std::unordered_map<int, std::string> _code_to_desc;std::unordered_map<std::string, func_t> _service_list;
};
#include"TcpServer.hpp"
#include"http.hpp"HttpResponse Login(HttpRequest &req)
{HttpResponse resp;std::cout << "外部已经拿到了参数了: "<< std::endl;req.GetResuestBody();std::cout << "####################### "<< std::endl;resp.AddCode(200, "OK");resp.AddBodyText("<html><h1>result done!</h1></html>");// username=helloworld&userpasswd=123456// 1. pipe// 2. dup2// 3. fork();// 4. exec* -> python, PHP, 甚至是Java!return resp;
}
int main(int argc,char* argv[])
{if(argc<2){std::cerr<<"Usage:"<<argv[0]<<"Server port"<<std::endl;exit(0);}uint16_t port=std::stoi(argv[1]);HttpServer http;http.InsertService("/login",Login);std::unique_ptr<TcpServer> tsvr=std::make_unique<TcpServer>(std::bind(&HttpServer::HandlerHttpRequest,&http,std::placeholders::_1),port);tsvr->Run();return 0;
}

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

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

相关文章

SAP学习笔记 - 开发04 - Fiori UI5 开发环境搭建

上一章学习了 CDSView开发环境的搭建&#xff0c;以及CDSView相关的知识。 SAP学习笔记 - 开发03 - CDSView开发环境搭建&#xff0c;Eclipse中连接SAP&#xff0c;CDSView创建-CSDN博客 本章继续学习SAP开发相关的内容&#xff0c; - Fiori UI5的开发环境搭建 - 安装VSCode …

百度飞将 paddle ,实现贝叶斯神经网络 bayesue neure network bnn,aistudio公开项目 复现效果不好

论文复现赛&#xff1a;贝叶斯神经网络 - 飞桨AI Studio星河社区 https://github.com/hrdwsong/BayesianCNN-Paddle 论文复现&#xff1a;Weight Uncertainty in Neural Networks 本项目复现时遇到一个比较大的问题&#xff0c;用pytorch顺利跑通源代码后&#xff0c;修改至pad…

【Python报错已解决】 AttributeError: ‘move_to‘ requires a WebElement

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 前言一、问题描述1.1 报错示例1.2 报错分析1.3 解决思路 二、解决方法2.1 方法一&#xff1a;检查元素选择器2.2 方法…

828华为云征文|华为云Flexus X实例docker部署rancher并构建k8s集群

828华为云征文&#xff5c;华为云Flexus X实例docker部署rancher并构建k8s集群 华为云最近正在举办828 B2B企业节&#xff0c;Flexus X实例的促销力度非常大&#xff0c;特别适合那些对算力性能有高要求的小伙伴。如果你有自建MySQL、Redis、Nginx等服务的需求&#xff0c;一定…

一款支持同一个屏幕界面同时播放多个视频的视频播放软件

GridPlayer 是一款基于 VLC 的免费开源跨平台多视频同步播放工具&#xff0c;支持在一块屏幕上同时播放多个视频。其主要功能包括&#xff1a; 多视频播放&#xff1a;用户可以在一个窗口中同时播放任意数量的视频&#xff0c;数量仅受硬件性能限制。支持多种格式和流媒体&…

java实现,PDF转换为TIF

目录 ■JDK版本 ■java代码・实现效果 ■POM引用 ■之前TIF相关的问题&#xff08;两张TIF合并&#xff09; ■对于成果物TIF&#xff0c;需要考虑的点 ■问题 ■问题1&#xff1a;无法生成TIF&#xff0c;已解决 ■问题2&#xff1a;生成的TIF过大&#xff0c;已解决 …

vue3 自定义指令 directive

1、官方说明&#xff1a;https://cn.vuejs.org/guide/reusability/custom-directives 除了 Vue 内置的一系列指令 (比如 v-model 或 v-show) 之外&#xff0c;Vue 还允许你注册自定义的指令 (Custom Directives)。 我们已经介绍了两种在 Vue 中重用代码的方式&#xff1a;组件和…

QT 编译报错:C3861: ‘tr‘ identifier not found

问题&#xff1a; QT 编译报错&#xff1a;C3861&#xff1a; ‘tr’ identifier not found 原因 使用tr的地方所在的类没有继承自 QObject 类 或者在不在某一类中&#xff0c; 解决方案 就直接用类名引用 &#xff1a;QObject::tr( )

ApacheKafka中的设计

文章目录 1、介绍1_Kafka&MQ场景2_Kafka 架构剖析3_分区&日志4_生产者&消费者组5_核心概念总结6_顺写&mmap7_Kafka的数据存储形式 2、Kafka的数据同步机制1_高水位&#xff08;High Watermark&#xff09;2_LEO3_高水位更新机制4_副本同步机制解析5_消息丢失问…

matplotlib中文乱码问题

在使用Matplotlib进行数据可视化的过程中&#xff0c;经常会遇到中文乱码的问题。显示乱码是由于编码问题导致的&#xff0c;而matplotlib 默认使用ASCII 编码&#xff0c;但是当使用pyplot时&#xff0c;是支持unicode编码的&#xff0c;只是默认字体是英文字体&#xff0c;导…

GraphPad Prism 10 for Mac/Win:高效统计分析与精美绘图的科学利器

GraphPad Prism 10 是一款专为科研工作者设计的强大统计分析与绘图软件&#xff0c;无论是Mac还是Windows用户&#xff0c;都能享受到其带来的便捷与高效。该软件广泛应用于生物医学研究、实验设计和数据分析领域&#xff0c;以其直观的操作界面、丰富的统计方法和多样化的图表…

【HuggingFace Transformers】OpenAIGPTModel源码解析

OpenAIGPTModel源码解析 1. GPT 介绍2. OpenAIGPTModel类 源码解析 说到ChatGPT&#xff0c;大家可能都使用过吧。2022年&#xff0c;ChatGPT的推出引发了广泛的关注和讨论。这款对话生成模型不仅具备了强大的语言理解和生成能力&#xff0c;还能进行非常自然的对话&#xff0c…

MapSet之二叉搜索树

系列文章&#xff1a; 1. 先导片--Map&Set之二叉搜索树 2. Map&Set之相关概念 目录 前言 1.二叉搜索树 1.1 定义 1.2 操作-查找 1.3 操作-新增 1.4 操作-删除(难点) 1.5 总体实现代码 1.6 性能分析 前言 TreeMap 和 TreeSet 是 Java 中基于搜索树实现的 M…

图形语言传输格式glTF和三维瓦片数据3Dtiles(b3dm、pnts)学习

文章目录 一、3DTiles二、b3dm三、glTF1.glTF 3D模型格式有两种2.glTF 场景描述结构和坐标系3.glTF的索引访问与ID4.glTF asset5.glTF的JSON结构scenesscene.nodes nodesnodes.children transformations对外部数据的引用buffers 原始二进制数据块&#xff0c;没有固有的结构或含…

表单项标签简单学习

目录 1. 单选框 radio​编辑​编辑​编辑​编辑 2. 复选框 checkbox ​编辑​编辑​编辑 3. 隐藏域 hidden 4. 多行文本框 textarea​编辑​编辑 5. 下拉框 select​编辑​编辑 6. 选择头像​编辑​编辑 <!DOCTYPE html> <html lang"en"> <head&…

自用NAS系列1-设备

拾光坞 拾光坞多账号绑定青龙面板SMBWebdav小雅alist下载到NASDocker安装迅雷功能利用qBittorrentEEJackett打造一站式下载工具安装jackett插件 外网访问内网拾光客户端拾光穿透公网ipv6路由器配置ipv6拾光坞公网验证拾光坞域名验证 拾光坞 多账号绑定 手机注册拾光坞账号&am…

GEE数据集:加拿大卫星森林资源调查 (SBFI)-2020 年加拿大森林覆盖、干扰恢复、结构、物种、林分年龄以及 1985-2020 年林分替代干扰的信息

目录 简介 数据集后处理 数据下载链接 矢量属性 代码 代码链接 引用 许可 网址推荐 0代码在线构建地图应用 机器学习 加拿大卫星森林资源调查 (SBFI) 简介 卫星森林资源清查&#xff08;SBFI&#xff09;提供了 2020 年加拿大森林覆盖、干扰恢复、结构、物种、林分…

海外云手机是否适合运营TikTok?

随着科技的迅猛发展&#xff0c;海外云手机逐渐成为改变工作模式的重要工具。这种基于云端技术的虚拟手机&#xff0c;不仅提供了更加便捷、安全的使用体验&#xff0c;还在电商引流和海外社媒管理等领域展示了其巨大潜力。那么&#xff0c;海外云手机究竟能否有效用于运营TikT…

828华为云征文 | Flexus X 实例服务器网络性能深度评测

引言 随着互联网应用的快速发展&#xff0c;网络带宽和性能对云服务器的表现至关重要。在不同的云服务平台上&#xff0c;即便配置相同的带宽&#xff0c;实际的网络表现也可能有所差异。因此&#xff0c;了解并测试服务器的网络性能变得尤为重要。本文将以华为云X实例服务器为…

Open-Sora代码详细解读(1):解读DiT结构

Diffusion Models专栏文章汇总&#xff1a;入门与实战 前言&#xff1a;目前开源的DiT视频生成模型不是很多&#xff0c;Open-Sora是开发者生态最好的一个&#xff0c;涵盖了DiT、时空DiT、3D VAE、Rectified Flow、因果卷积等Diffusion视频生成的经典知识点。本篇博客从Open-S…