Linux之Http协议分析以及cookie和session

Linux之Http协议分析以及cookie和session

  • 一.分析请求行与响应行
    • 1.1请求行
    • 1.1.1资源的URL路径
    • 1.1.2常见的方法
    • 1.2响应行
  • 二.cookie和session
    • 2.1cookie
    • 2.2session

一.分析请求行与响应行

在我们简单了解了请求和响应的格式以及模拟实现了请求和响应后我们已经可以通过网页来访问我们的服务器从而获得一些简单的信息,但是这些还只是http协议的冰山一角,今天我们还需要继续分析请求和响应中的首行从而来更了解http协议。

1.1请求行

请求行中一共分为三部分:方法+URL路径+版本号。其中版本号我们在上篇文章中已经谈过其中的内容也相对来说不那么重要,而方法我们也只要会用最常见的两种以及记住其余的大致作用即可但是URL路径却是我们最需要谈的。

1.1.1资源的URL路径

我们先来再看一下我们的请求行中存储的URL路径
在这里插入图片描述
这里的我只用了IP:端口号的方式在浏览器上访问服务器而这时URl路径显示的就只是一个/符号那么如果我在IP:端口号的基础上加上路径呢?那时候请求行中的URL路径会发生改改变吗?
在这里插入图片描述
我将路径改成了/a/b后很明请求行中的URL路径也发生了改变,就说明如果我们访问时在端口后不加上路径那么就会默认访问/路径下的资源,如果自己添加了路径就会访问该路径下的资源。可是问题是这个/是什么呢?为什么不添加路径就会默认访问该路径下的资源?

http协议规定的是如果我们不自己添加访问的路径,那么就会默认访问web根目录而web根目录通俗一点的话就是访问网址的首页那么具体是访问根目录下的哪个资源呢?其实我们默认访问的是/index.html。
可能大家会说我们模拟实现的代码里并没有什么index.html资源啊而且你说自己填路径和访问web根目录时访问的资源是不一样的那么为什么我们上面的图片里都是一样的helloworld呢?这是我们编写的代码的缘故我们现在并没有对URL路径加以分析而且一股脑的对于访问都塞一个一样的响应回去所以导致如此结果。

那么我们要如何区分URL路径而且那些不同路径下的资源又要怎么存放呢?
在Linux中一切皆文件所以大家很容易可以想到我们可以创建几个不同的文件来存放资源到时候只要我们对URL路径进行分析再让其去访问其中的内容即可。所以我们可以创建一共目录来存放这些不同路径下的资源,而这个目录在网络编程下一般都是设为wwwroot也可以是webroot。接下来我就来给大家模拟实现一下我们所说的这个方法。

// HttpProtocol.hpp
#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <fstream>const static std::string HttpSep = "\r\n";// 默认访问的资源
const static std::string homepage = "index.html";
const static std::string wwwroot = "./wwwroot";class HttpRequest
{
public:HttpRequest(): _blankline(HttpSep), _path(wwwroot){}~HttpRequest(){}bool Getline(std::string &request, std::string *line){// 请求行\r\n请求报头\r\n空行\r\n请求正文// 在请求中查找HttpSepauto pos = request.find(HttpSep);if (pos == std::string::npos){return false;}// 分割请求*line = request.substr(0, pos);request.erase(0, pos + HttpSep.size());return true;}bool Deserializa(std::string &request){std::string line;// 判断是否只有请求行bool ok = Getline(request, &line);if (!ok){return false;}_req_line = line;// 一行一行的分割请求while (true){bool ok = Getline(request, &line);if (ok && line.empty()){// 如果分割行成功并且line中存储是空行// 说明request只剩下了正文(无论正文是否有内容)_req_content = request;break;}else if (ok && !line.empty()){// 如果分割成功并且line内有内容// 说明line中存储的是请求报头中的一行_req_header.push_back(line);}else{break;}}return true;}void DebugHttp(){std::cout << "_req_line:" << _req_line << std::endl;std::cout << "_req_header:" << std::endl;for (auto &line : _req_header){std::cout << "---> " << line << std::endl;}std::cout << "_req_blank: " << _blankline << std::endl;std::cout << "_req_content: " << _req_content << std::endl;std::cout << "Method: " << _method << std::endl;std::cout << "url: " << _url << std::endl;std::cout << "path: " << _path << std::endl;std::cout << "http_version: " << _http_version << std::endl;}// 分析请求行void AnalyseReqline(){// 大家可以用find来查找空格之后再进行分割的方法// 但是我这里就使用C++中专门处理字符串的输入输出流stringstream// 使用sstream需要包含头文件<sstream>std::stringstream ss(_req_line);// 请求行:method path version// 而stringstream的插入会自动以空格为分割ss >> _method >> _url >> _http_version;// 如果_url为根目录就还需要添加默认的资源if (_url == "/"){_path += _url;_path += homepage;}else{// 不是根目录则直接加URL路径即可_path += _url;}}// 分析后缀void AnalyseSuffix(){// index.html我们只需要拿到.和其之后的字符即可auto pos = _path.rfind(".");if (pos != std::string::npos){_suffix = _path.substr(pos);}else{_suffix = ".html";}}// 对资源文件做处理std::string GetFileContentHelper(const std::string &path){// 因为是对文件做处理所以使用ifstreamstd::cout << "this1" << std::endl;std::cout << path << std::endl;std::ifstream in(path, std::ios::binary);std::cout << "this2" << std::endl;// 打开文件,失败返回""成功则读取其中内容if (!in.is_open()){std::cout << "this3" << std::endl;return "";}std::cout << "this4" << std::endl;std::string content;std::string line;// 一行一行的读取while (std::getline(in, line)){content += line;}in.close();return content;}std::string GetFileContent(){return GetFileContentHelper(_path);}void Analyse(){// 1.分析请求行AnalyseReqline();// 2.分析后缀AnalyseSuffix();}std::string GetUrl(){return _url;}std::string GetPath(){return _path;}std::string GetSuffix(){return _suffix;}private:// 根据请求格式我们可以设计出四个变量std::string _req_line;                // 请求行std::vector<std::string> _req_header; // 请求报头std::string _blankline;               // 空行std::string _req_content;             // 请求正文// 分析请求行后std::string _method;       // 方法std::string _url;          // 路径std::string _http_version; // 版本// 分析URL后将其分为路径和后缀两部分// 因为资源有很多种类所以我们需要判别资源的种类再加以不同处理std::string _path;std::string _suffix;
};
// httpserver.cc
#include <iostream>
#include <memory>#include "HttpProtocol.hpp"
#include "Tcpserver.hpp"// 文件的后缀决定了文件的类型,http协议需要响应报头中包含正文的文件类型
std::string SuffixToType(const std::string &suffix)
{if (suffix == ".html" || suffix == ".htm"){return "text/html";}else if (suffix == ".png"){return "image/png";}else if (suffix == ".jpg"){return "image/jpeg";}else{return "Unknown";}
}std::string HandleMethod(std::string request)
{HttpRequest http_req;http_req.Deserializa(request);http_req.Analyse();http_req.DebugHttp();std::string content = http_req.GetFileContentHelper(http_req.GetPath());if (!content.empty()){std::string httpstatusline = "Http/1.0 200 OK\r\n";std::string httpheader = "Content-Length: " + std::to_string(content.size()) + "\r\n"; // 正文的大小httpheader += "Content-Type: " + SuffixToType(http_req.GetSuffix()) + "\r\n";          // 正文的类型httpheader += "\r\n";std::string httpresponse = httpstatusline + httpheader + content;return httpresponse;}return "";
}int main(int argc, char *argv[])
{if (argc != 2){std::cout << "Usge:\n"<< argv[0] << " port" << std::endl;return 0;}uint16_t localport = std::stoi(argv[1]);std::unique_ptr<TcpServer> svr(new TcpServer(localport, HandleMethod));svr->Loop();return 0;
}
}

在这里插入图片描述

我们的资源有很多种类型,一般常见的就是.html,.png等等。对应.html文件的编写是我们前端人员的工作所以大家可以自行去搜索学习一下。
在这里插入图片描述

这是我们现在用浏览器访问服务器web根目录资源的样子,大家可以发现我们的图片加载不出来这是因为我们的图片在解析的时候是全二进制的但是我们如今使用的对资源文件做处理是针对于文本文件的如.html文件所以我们还需要将处理方法改进成通用方法才行。

// 对资源文件做处理std::string GetFileContentHelper(const std::string &path){// 文本//  // 因为是对文件做处理所以使用ifstream//  std::ifstream in(path, std::ios::binary);//  // 打开文件,失败返回""成功则读取其中内容//  if (!in.is_open())//  {//      return "";//  }// std::string content;// std::string line;// // 一行一行的读取// while (std::getline(in, line))// {//     content += line;// }// in.close();// return content;// 通用方法std::ifstream in(path, std::ios::binary);if (!in.is_open()){return "";}// 跳转到in的末尾in.seekg(0, in.end);// 将in的大小填入filesize中int filesize = in.tellg();// 跳转到in的开头in.seekg(0, in.beg);std::string content;// 设置content的大小content.resize(filesize);// 将in的内容填入到content中in.read((char *)content.c_str(), filesize);in.close();return content;}

在这里插入图片描述

1.1.2常见的方法

在我们了解常见的方法前我们需要先知道上网这个行为的本质是什么,本质就是我们从网上上获取资源或者我们向服务器传送参数也就是资源,而我们最常用的GET方法和POST方法就包含了这两方面。

  1. GET方法
    通常用来获取资源也可以通过URL地址来传参,但是传输的参数私密性不强。传参这个动作需要依靠我们html文件的表单来实现
    在这里插入图片描述
    那么我们向里面输入信息后URL地址会发生怎么样的变化呢?在这里插入图片描述
    那么我们如果向里面填写信息呢信息会被加入到URL里吗?
    在这里插入图片描述
    至于为什么私密性不强我想大家一眼就看出来了因为在URL地址中所有人都能看见当然私密性不强了。

  2. POST方法
    通常用来上传数据但是POST方法上传数据的形式和GET不同,POST方法不会将数据存在URL地址中而是存于请求正文中传给服务器,通过请求正文传参那么肉眼可见的POST传参的私密性会好一点。
    在这里插入图片描述

同时由于GET是利用URL传参所以会受到URL自身被规定的长度所限制但是POST方法则不会,虽然POST方法的私密性比GET方法好一点但是其实两者都不安全。那么我们想要我们传输的账号密码安全就必须经过加密和解密的过程这也就形成了我们之后的https协议。

至于其余的方法我就直接用别的博主写的来列给大家看看了因为都不是很重要

  1. HEAD
    获得报文首部,类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头。欲判断某个资源是否存在,我们通常使用GET,但这里用HEAD则意义更加明确。
    向服务器获取某些易过期或丢失大型文件时,可用HEAD方式查询资源是否存在。

  2. OPTIONS
    询问支持的方法客户端询问服务器可以提交哪些请求方法。这个方法很有趣,它用于获取当前URL所支持的方法。若请求成功,则它会在HTTP头中包含一个名为“Allow”的头,值是所支持的方法,如“GET, POST”。
    极少使用。

  3. PUT
    传输文件。从客户端向服务器传送的数据取代指定的文档的内容,即指定上传资源存放路径。这个方法比较少见。HTML表单也不支持这个。本质上来讲, PUT和POST极为相似,都是向服务器发送数据,但它们之间有一个重要区别,PUT通常指定了资源的存放位置,而POST则没有,POST的数据存放位置由服务器自己决定。

  4. PATCH
    局部更新文件,是对 PUT 方法的补充,用来对已知资源进行局部更新 。
    极少使用。

  5. DELETE
    删除文件。请求服务器删除指定的资源。
    基本上这个也很少见,不过还是有一些地方比如amazon的S3云服务里面就用的这个方法来删除资源。

  6. TRACE
    追踪路径,回显服务器收到的请求,客户端可以对请求消息的传输路径进行追踪,TRACE方法是让Web服务器端将之前的请求通信还给客户端的方法。主要用于测试或诊断。
    极少使用。

  7. CONNECT
    要求用隧道协议连接代理,HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。CONNECT方法要求在与代理服务器通信时建立隧道,实现用隧道协议进行TCP通信。主要使用SSL(安全套接层)和TLS(传输层安全)协议把通信内容加密后经网络隧道传输。
    极少使用。

原文链接:https://blog.csdn.net/demo_yo/article/details/123596028

1.2响应行

对应响应行的分析就简单多了我们只需要分析状态码即可,状态码也很好理解就是告诉你完成的情况或者有一些特殊情况。所以我直接给状态码贴给大家我拿其中比较典型的几个给大家说一说然后我们也还需要模拟实现一下不同状态码的情况。
在这里插入图片描述
一共五大类状态码分别以12345开头每大类中还需要细分,我就给每大类中典型的跟大家解释一下这样大家也对五种状态码有个概念。

  1. 信息状态码(1xx)
    信息状态码我们只需要记住100即可,100状态码出现的情况一般是当我们从客户端往服务器传输数据时过大服务器无法一次性接收完全,当服务器接收了一半之后就会传出100状态码来告诉客户端你可以继续上传数据了。所以100状态码就是继续的含义。
  2. 成功状态码(2xx)
    成功状态码我们需要记住200和204。200很简单就是告诉你请求被处理成功了而204也是告诉你请求被处理成功了但是没有结果返回。
  3. 重定向状态码(3xx)
    重定向状态码需要大家理解并且记住301和302分别是永久重定向和临时重定向。首先我们来解释一下什么是http里的重定向,我给大家举两个例子一个是当我们创建的网站过期了之后我们需要换IP地址换域名了但是用户只记得旧网站的网址另外一个是我们在各种的网站中会登入自己的账号有时候在登入账号后会自动条状到自己账号的主页。第一个需要我们在将旧网站重定向到新网站从而达成用户只要登入旧网站就会自动跳转到新网站上,第二个是如何完成的呢也就像我们刚刚展示表单时我们把登入按钮重定向到用户自己的主页上这样这要我们登入成功了就会自动跳转。从这两个例子中我们可以发现重定向的作用一般就是从一个网址跳转到另外一个网址上,并且这两个例子中的重定向还不一样第一个例子是永久重定向因为旧网站不用了过期了只用新网站现在,第二个例子是临时重定向我们只需要在当时让用户完成登入后跳转到主页即可。
  4. 客户端错误状态码(4xx)
    客户端错误状态码则需要大家记住403和404这两个即可。404状态码其实算这些状态码里比较常见的了,我们只需要访问一些不存在的网站就很容易得出这个状态码。在这里插入图片描述
    而403状态码则是我们如果访问了一些我们没有全新的网址就会出现。

这两个状态码是很好理解的但是比较难理解的是4xx状态码为什么叫做客户端错误状态码,明明是我访问你们服务器为什么变成我错了呢?其实从这两个状态码的名字里就能看出来一个是访问不存在的网址一个是访问没权限的网址,从服务器的角度上我明明有这么多页面可以给你看你偏偏找一个不存在的网址或者找一个你没权限的网址,我用心用力的给你服务你这不是给我找茬吗。所以这是用户自己作的妖当然就是客户端错误状态码了。

  1. 服务器错误状态码(5xx)
    这个状态码需要大家记住500和503,服务器错误状态码平时应该很少见因为我们如今使用的软件大多都是一些大厂发行的他们的服务器一般都是比较稳定的除了个别公司。500状态码的含义是服务器崩溃或者数据库崩溃导致页面无法加载出来,503状态码是服务器正在维护或者过载导致暂时无法处理请求。

在了解了这些状态码后我们也可以来模拟实现一下这些状态码对应的情况

const static std::string Space = " ";// 响应
class HttpResponse
{
public:HttpResponse(): _version("HTTP/1.0"), _status_code(200), _status_code_desc("OK"), _blankline(HttpSep){}~HttpResponse(){}void SetCode(int status_code){_status_code = status_code;}void SetDesc(std::string status_code_desc){_status_code_desc = status_code_desc;}void MakeStatusLine(){_status_line = _version + Space + std::to_string(_status_code) + Space + _status_code_desc;}void Addheader(std::string header){_resp_header.push_back(header);}void Addcontent(std::string content){_resp_content = content;}std::string Serializa(){std::string response_str = _status_line;for (auto header : _resp_header){response_str += header;}response_str += _blankline;response_str += _resp_content;return response_str;}private:std::string _status_line;              // 状态行std::vector<std::string> _resp_header; // 响应报头std::string _blankline;                // 空行std::string _resp_content;             // 响应正文std::string _version;          // 版本int _status_code;              // 状态码std::string _status_code_desc; // 状态码解释
};
// Tcpserver.cc
#include <iostream>
#include <memory>#include "HttpProtocol.hpp"
#include "Tcpserver.hpp"// 文件的后缀决定了文件的类型,http协议需要响应报头中包含正文的文件类型
std::string SuffixToType(const std::string &suffix)
{if (suffix == ".html" || suffix == ".htm"){return "text/html";}else if (suffix == ".png"){return "image/png";}else if (suffix == ".jpg"){return "image/jpeg";}else{return "Unknown";}
}std::string CodeToDesc(int code)
{if (code == 200){return "OK";}else if (code == 301){return "Moved Permanently";}else if (code == 307){return "Temporary Redirect";}else if (code == 403){return "Forbidden";}else if (code == 404){return "Not Found";}else if (code == 500){return "Internal Server Error";}else{return "Unknown";}
}std::string HandleMethod(std::string request)
{HttpRequest http_req;http_req.Deserializa(request);http_req.Analyse();http_req.DebugHttp();int code = 200;std::string content = http_req.GetFileContentHelper(http_req.GetPath());if (content.empty()){code = 404;content = http_req.GetFile404();}HttpResponse response;// 设置状态码response.SetCode(code);// 设置状态码描述response.SetDesc(CodeToDesc(code));// 生成状态行response.MakeStatusLine();// 插入响应报头std::string content_len_str = "Content-Length: " + std::to_string(content.size()) + "\r\n"; // 正文的大小response.Addheader(content_len_str);std::string content_type_str = "Content-Type: " + SuffixToType(http_req.GetSuffix()) + "\r\n"; // 正文的类型response.Addheader(content_type_str);// 插入响应正文response.Addcontent(content);// 序列化return response.Serializa();
}int main(int argc, char *argv[])
{if (argc != 2){std::cout << "Usge:\n"<< argv[0] << " port" << std::endl;return 0;}uint16_t localport = std::stoi(argv[1]);std::unique_ptr<TcpServer> svr(new TcpServer(localport, HandleMethod));svr->Loop();return 0;
}

二.cookie和session

我们在学习了GET和POST方法后知道我们是可以通过请求正文给服务器传输信息的从而达成登入的操作但是不知道大家在日常使用中有没有发现我们只要登入了某个网站之后的一段时间我们就不需要再输入账号密码来登入了,这是为什么呢?
我们很容易就能想到一个答案:Http协议记住了我们的账号密码这样只要我们登入过一次之后就不用再登入了。但是这是错的这是因为Http协议是无状态无连接的,什么叫做无状态无连接呢也就是Http协议是不记住自己的历史的所以每次打开一个网站理论上是都是第一次打开因为http协议不记得你之前来过那不就是当第一次吗。这个问题也就导致了理论上我们每次都需要重新登入就算我们答应网站的公司也不答应啊,这样的操作不就很花费用户的时间和耐心也就会让网站的流量下降盈利也就下降了。所以针对这种情况延申出了两种解决方法:cookie和session,准确的来说session是在cookie的基础上改进了。

2.1cookie

想要解决这个问题其实很简单我们只需要在第一次登入的时候通过POST方法将账号密码传入到服务器中之后服务器再在响应报头中添加进去返回给浏览器,这样浏览器中就存有了你的账号密码之后每次再登入对应的网址的时候浏览器只要将你的账号密码通过请求报头传入到服务器让服务器查询是否有此用户即可。而cookie就是浏览器保存起来的报头形式的账号密码。
在这里插入图片描述
但是这样的解决方案依然有问题:浏览器保存的都是我真实的私密信息但是浏览器中的信息太过容易被盗取只要有人获得了我的私密信息就可以随意使用我的账号了。这就造成了用户的隐私安全问题。
在这里插入图片描述
我们现在使用的都是https协议所以cookie都是被加密过的但是在以前只用http协议时cookie信息是明晃晃的存在浏览器中的。

2.2session

所以有人为了避免这种问题将cookie改进成了session,而改进的地方就在于当服务器接收了来自浏览器POST的数据后它会通过这个数据生成一个结构体session和一个独一无二的sessionid并且这个session中还会存放用户的状态例如地理位置等等,之后就将账号密码再传回给浏览器而是将这个sessionid传给浏览器。浏览器只需要保存这个sessionid在下次登入的时候将sessionid传给服务器,服务器再进行查找判断即可。这样的好处是浏览器保存的就不是用户的真实隐私而是一串独特的sessionid并且在session中你不仅可以通过账号密码来判断用户是否合法还可以通过用户此次登入的地理位置和上一次的地理位置的距离来判断。
在这里插入图片描述
这样就解决了用户的隐私安全问题。

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

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

相关文章

【漫话机器学习系列】085.自助采样法(Bootstrap Sampling)

自助采样法&#xff08;Bootstrap Sampling&#xff09; 1. 引言 在统计学和机器学习领域&#xff0c;数据的充足性直接影响模型的性能。然而&#xff0c;在许多实际场景中&#xff0c;我们可能无法获得足够的数据。为了解决这个问题&#xff0c;自助采样法&#xff08;Boots…

nodejs - vue 视频切片上传,本地正常,线上环境导致磁盘爆满bug

nodejs 视频切片上传&#xff0c;本地正常&#xff0c;线上环境导致磁盘爆满bug 原因&#xff1a; 然后在每隔一分钟执行du -sh ls &#xff0c;发现文件变得越来越大&#xff0c;即文件下的mp4文件越来越大 最后导致磁盘直接爆满 排查原因 1、尝试将m3u8文件夹下的所有视…

公司配置内网穿透方法笔记

一、目的 公司内部有局域网&#xff0c;局域网上有ftp服务器&#xff0c;有windows桌面服务器&#xff1b; 在内网环境下&#xff0c;是可以访问ftp服务器以及用远程桌面登录windows桌面服务器的&#xff1b; 现在想居家办公时&#xff0c;也能访问到公司内网的ftp服务器和win…

ZU47DR 100G光纤 高性能板卡

简介 2347DR是一款最大可提供8路ADC接收和8路DAC发射通道的高性能板卡。板卡选用高性价比的Xilinx的Zynq UltraScale RFSoC系列中XCZU47DR-FFVE1156作为处理芯片&#xff08;管脚可以兼容XCZU48DR-FFVE1156&#xff0c;主要差别在有无FEC&#xff08;信道纠错编解码&#xff0…

【自然语言处理】利用Memory Layer替换Transformer中的FFN

论文地址&#xff1a;https://arxiv.org/pdf/2412.09764 相关博客 【自然语言处理】利用Memory Layer替换Transformer中的FFN 【自然语言处理】【大模型】BitNet&#xff1a;用1-bit Transformer训练LLM 【自然语言处理】BitNet b1.58&#xff1a;1bit LLM时代 【自然语言处理】…

ChunkKV:优化 KV 缓存压缩,让 LLM 长文本推理更高效

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

台湾精锐APEX减速机在半导体制造设备中的应用案例

半导体制造设备对传动系统的精度、可靠性和稳定性要求极高&#xff0c;台湾精锐APEX减速机凭借其低背隙、高精度和高刚性等优势&#xff0c;在半导体制造设备中得到了广泛应用。 案例一&#xff1a;晶圆切割设备 1.应用场景 在晶圆切割过程中&#xff0c;设备需要高精度的运…

如何为win10本地部署的deepseek创建一个快捷方式

简介&#xff1a;在桌面上创建一个快捷方式&#xff0c;双击即可实现打开终端并且输入ollama run的命令。 在win10系统下&#xff0c;本地部署了deepseek之后&#xff0c;每次需要打开powershell&#xff0c;然后再手动输入指令 ollama run deepseek-r1:1.5b 要想实现一个桌面…

解锁Rust:融合多语言特性的编程利器

如果你曾为理解Rust的特性或它们之间的协同工作原理而苦恼,那么这篇文章正是为你准备的。 Rust拥有许多令人惊叹的特性,但这些特性并非Rust所独有。实际上,Rust巧妙地借鉴了众多其他语言的优秀特性,并将它们融合成了一个完美的整体。深入了解Rust这些重要特性的来源以及它是…

【阅读笔记】信息熵自动曝光An Automatic Exposure Algorithm Based on Information Entropy

一、算法背景 信息熵作为衡量图像信息量的重要指标&#xff0c;能够反映图像的细节丰富程度。通过基于信息熵的自动曝光算法&#xff0c;可以自动调整曝光时间&#xff0c;使图像包含更多信息&#xff0c;从而提高图像质量。 灰度直方图在各个灰度值上分布越均匀&#xff0c;…

2025我的第二次社招,写在春招之季

先说一个好消息&#xff0c;C那些事 4w star了&#xff01; 前面断更了一个月&#xff0c;本篇文章就可以看到原因&#xff0c;哈哈。 大家好&#xff0c;我叫光城&#xff0c;腾讯实习转正做后端开发&#xff0c;后去小公司做数据库内核&#xff0c;经过这几年的成长与积累&am…

运用Deek Seeker协助数据分析

我的数据源有两张表&#xff0c;一个是每日销售表(字段有日期、产品名称、实际销量)&#xff0c;一个是每月目标表(字段有年度月份、产品名称、目标销量);我的需求是&#xff0c;按月、按年来统计每个产品的目标完成情况请问用PowerBl进行分析&#xff0c;应该如何建立数据模型…

【设计模式】【行为型模式】策略模式(Strategy)

&#x1f44b;hi&#xff0c;我不是一名外包公司的员工&#xff0c;也不会偷吃茶水间的零食&#xff0c;我的梦想是能写高端CRUD &#x1f525; 2025本人正在沉淀中… 博客更新速度 &#x1f4eb; 欢迎V&#xff1a; flzjcsg2&#xff0c;我们共同讨论Java深渊的奥秘 &#x1f…

【高级架构师】多线程和高并发编程(三):锁(中)深入ReentrantLock

文章目录 3、深入ReentrantLock3.1 ReentrantLock和synchronized的区别3.2 AQS概述3.3 加锁流程源码剖析3.3.1 加锁流程概述3.3.2 三种加锁源码分析3.3.2.1 lock方法3.3.2.2 tryLock方法3.3.2.3 lockInterruptibly方法 3.4 释放锁流程源码剖析3.4.1 释放锁流程概述3.4.2 释放锁…

WPF 进度条(ProgressBar)示例一

本文讲述&#xff1a;WPF 进度条(ProgressBar)简单的样式修改和使用。 进度显示界面&#xff1a;使用UserControl把ProgressBar和进度值以及要显示的内容全部组装在UserControl界面中&#xff0c;方便其他界面直接进行使用。 <UserControl x:Class"DefProcessBarDemo…

Android studio怎么创建assets目录

在Android Studio中创建assets文件夹是一个简单的步骤&#xff0c;通常用于存储不需要编译的资源文件&#xff0c;如文本文件、图片、音频等 main文件夹&#xff0c;邮件new->folder-assets folder

工业相机在工业生产制造过程中的视觉检测技术应用

随着技术不断发展以及工业4.0时代的到来&#xff0c;利用工业相机进行视觉检测技术已经成为制造业不可或缺的一部分。通过结合先进的计算机视觉、AI算法和自动化设备&#xff0c;工业视觉检测为生产线质量控制和效率提升提供了革命性的解决方案。 一、什么是工业视觉检测技术 …

快速上手Vim的使用

Vim Linux编辑器-vim使用命令行模式下所有选项都可以带数字底行模式可视块模式&#xff08;ctrlV进入&#xff09; Linux编辑器-vim使用 Vim有多种模式的编辑器。能帮助我们很快的进行代码的编辑&#xff0c;甚至完成很多其他事情。 默认情况下我们打开vim在命令模式下&#x…

数据结构-基础

1、概念&#xff1a; 程序 数据结构 算法 2、程序的好坏 可读性&#xff0c;稳定性&#xff0c;扩展性&#xff0c;时间复杂度&#xff0c;空间复杂度。 3、数据结构 是指存储、组织数据的方式&#xff0c;以便高效地进行访问和修改。通过选择适当的数据结构&#xff0c; 能…

本地部署DeepSeek(Mac版本,带图形化操作界面)

一、下载安装&#xff1a;Ollama 官网下载&#xff1a;Download Ollama on macOS 二、安装Ollama 1、直接解压zip压缩包&#xff0c;解压出来就是应用程序 2、直接将Ollama拖到应用程序中即可 3、启动终端命令验证 # 输入 ollama 代表已经安装成功。 4、下载模型 点击模型…