【计算机网络-应用层】解析HTTP会话保持:Cookie与Session的原理与实践

📚 博主的专栏

🐧 Linux   |   🖥️ C++   |   📊 数据结构  | 💡C++ 算法 | 🅒 C 语言  | 🌐 计算机网络

上篇文章:实现HTTP服务器

下篇文章:传输层协议-UDP

文章摘要
本文从HTTP协议的无状态特性出发,系统讲解了Cookie与Session技术如何协作实现用户会话保持。首先剖析HTTP无状态的含义及其局限性,结合案例说明无状态对用户身份识别的挑战。随后详细解析Cookie的定义、类型(内存级与文件级)、工作原理及安全性问题,并通过代码示例演示Cookie的写入、过期时间与路径设置。进一步引入Session技术,对比其与Cookie的差异,强调Session通过服务器端存储用户信息提升安全性,结合代码实现展示Session ID的生成与验证机制。最后总结Cookie与Session的协同应用场景及安全性优化策略,为开发者提供会话管理的实践指导。

目录

HTTP协议本身是无状态是什么意思?

HTTP协议本身是无连接是什么意思?

引入 HTTP Cookie

定义

cookie分为内存级(会话cookie)和文件级(持久cookie):

内存级(会话级):在浏览器关闭时失效

文件级(持久级):带有明确的过期日期或持续时间,可以跨多个浏览器会话存在。

工作原理

安全性

用途

通过代码来认识cookie:cookie的写入和自动提交

认识 cookie

接下来我们通过代码来谈论测试写入过期时间 

基本格式

完整的 Set-Cookie 示例

关于时间解释

区别:

给cookie设置上路径

写入多组cookie

其他可选属性的解释

单独使用 Cookie, 有什么问题?

Session

定义

工作原理

通过代码来理解:

Session.hpp,模拟实现session

安全性:

超时和失效:

用途:

总结:


本文章主要通过理论和实践相结合讲解,HTTP协议是如何进行登录时会话保持的。

HTTP协议本身是无状态是什么意思?

浏览器客户端给服务器端发送请求,请求一个网页a.html,服务器就会构建一个响应,正文部分就会携带上这个a.html,客户端就得到了这个a.html,但是关键是http是无状态的,当我们再次发送请求,仍然请求的是曾经已经请求过的某个资源,假如就是这个a.html, 但是,服务器并不会知道同一个客户端曾经向我请求过同一份资源,只能同样的再将资源携带返回。这就叫做无状态。

        浏览器会解决这种问题,会将请求的并获得的资源(网页、图片、css、js、视频音频),缓存在浏览器本身内部,下次访问的时候浏览器就不再发起网络请求,而是直接渲染出。

HTTP协议本身是无连接是什么意思?

HTTP协议通信本身不需要连接,HTTP的底层实现虽然是TCP,TCP是面向连接的,但是TCP的连接和HTTP的连接是两个维度的关系,因此TCP自己需要建立连接和HTTP并没有什

么关系。

举例:

各大视频网站的一部分视频可以免费观看,并且没有登陆的游客也可以观看。而有些视频电视剧则相反,不仅需要用户注册登录,还需要用户购买vip提升权限才能观看完整视频。

请注意,HTTP协议本身是无状态的,假如用户选择的视频是需要用户登录的,并且用户已经登录网站,观看这个视频后,又想观看其他视频(需登录的),每想看一个视频就需要发送一次请求,就需要再次用户身份识别,但由于HTTP协议本身是无状态的,因此不会知道用户历史上登陆过。

那么我们怎么能够更好的在用户访问网站资源的时候,时时刻刻标识一个网络用户的身份呢?

这时候,就需要cookie和session。

cookie和session技术的重要作用之一

会话管理:协助网站,在基于http协议基础之上,帮助网站标识一个用户的身份

比如我们访问B站,在登录过后,许久之后再次访问这个网站时,还是处于登录状态,这就有可能是使用了http协议结合cookie和session的会话保持技术(也有可能是某种登录保存技术)。浏览器和服务器互相协作,就能长时间保持用户在线,识别用户身份。

B 站登录和未登录

• 问题: B 站是如何认识我这个登录用户的?

通过cookie和session技术。

• 问题: HTTP 是无状态, 无连接的, 怎么能够记住我?

通过cookie和session技术。

引入 HTTP Cookie

定义

HTTP Cookie(也称为 Web Cookie、 浏览器 Cookie 或简称 Cookie) 是服务器发送到用户浏览器并保存在浏览器上的一小块数据, cookie会在浏览器之后向同一服务器再次发起请求时被携带并发送到服务器上(cookie是依赖于http)。 通常,它用于告知服务端两个请求是否来自同一浏览器, 如保持用户的登录状态、 记录用户偏好等。

向客户端写入信息的过程就叫做写入cookie,从此往后,客户端每发送请求都会携带这次写入的信息 。

在用户进行Http登录的时候(输入账号密码),在服务器端会对登录信息进行认证,之后服务器端会进行http响应,在进行应答前,会设置Set-Cookie(属于Http报头属性),写入用户基本信息(用户名、密码...),一旦登陆成功,得到的应答就会包含用户信息,浏览器会识别到set-Cookie。就会将用户基本信息,保存在浏览器内部,从此以后,浏览器在访问目标网站的时候,浏览器会给所有的http请求报头当中,将用户的基本信息作为http请求的一部分,拼接到http请求里。服务器每一次都能得到用户第一次登录时写入的信息。服务器每一次都能对用户身份进行合法性判别。

cookie分为内存级(会话cookie)和文件级(持久cookie):

内存级(会话级):在浏览器关闭时失效

浏览器本身也是一个进程,请求和响应在浏览器这里,实际都是对象,new出来的。同样的,当浏览器收到服务器端响应的数据时,可以暂时保存在浏览器进程,因此,浏览器进程是在内存当中的,当浏览器被关闭后,cookie数据失效,这就是内存级cookie。

文件级(持久级):带有明确的过期日期或持续时间,可以跨多个浏览器会话存在。

比如我们使用的chrome,edge等浏览器,是被我们安装在磁盘当中的,有自己的安装路径,因此也会存在日志、配置、以及临时数据,因此就会将一些cookie、session数据保存在文件当中,当浏览器关闭,对应的cookie数据仍然存在,因此在下一次(一周、一个月)访问时,仍然不需要登录。这就是文件级cookie。

在浏览器中找到cookie并删除响应数据:删除后需要再次登录

工作原理

  • 当用户第一次访问网站时, 服务器会在响应的 HTTP 头中设置 Set-Cookie字段, 用于发送 Cookie 到用户的浏览器。
  • 浏览器在接收到 Cookie 后, 会将其保存在本地(通常是按照域名进行存储) 。
  • 在之后的请求中, 浏览器会自动在 HTTP 请求头中携带 Cookie 字段, 将之前保存的 Cookie 信息发送给服务器

安全性

• 由于 Cookie 是存储在客户端的, 因此存在被篡改或窃取的风险

用途

○ 用户认证和会话管理(最重要)

○ 跟踪用户行为

○ 缓存用户偏好等

○ 比如在 chrome 浏览器下, 可以直接访问: chrome://settings/cookies

通过代码来认识cookie:cookie的写入和自动提交

git clone https://gitee.com/whb-helloworld/linux-plus-meal.git

请进入到这个目录下:里面的大多数程序的编写,在我的博客文章有讲解,有兴趣的朋友可以去看:

linux-plus-meal/http-cookie-session/cookie$

本篇文章重点讲解HttpProtocol.hpp中修改的代码 

运行代码:状态码、状态描述、以及正文部分,文件类型

被注释掉的代码中的函数: 向Set-Cookie中写入用户名

    std::string ProveCookieWrite() // 证明cookie能被写入浏览器{return "Set-Cookie: username=zhangsan;";}

会被添加到响应报文的响应头里:

        resp.AddHeader(ProveCookieWrite()); //测试cookie被写入与自动提交

我们可以在浏览器当中输入服务器公网ip:端口号,此时,再从浏览器查看cookie,由于我们没有添加写入cookie,因此是0个cookie。

当我们将resp.AddHeader(ProveCookieWrite());,这条的注释放开:

cookie就有了,并且我们可以查看服务器的获得的请求,我们再次发起请求时、刷新时,也是带有cookie的:

无论我们访问的是这个网站下的资源,只要有cookie:照样会显示helloworld

认识 cookie

○ HTTP 存在一个报头选项: Set-Cookie, 可以用来进行给浏览器设置 Cookie值。

○ 在 HTTP 响应头中添加, 客户端(如浏览器) 获取并自行设置并保存Cookie。

接下来我们通过代码来谈论测试写入过期时间 

当我们不写时间,cookie默认就是内存级的,写了时间,cookie就是文件级的

基本格式

Set-Cookie: <name>=<value>

其中 <name> 是 Cookie 的名称, <value> 是 Cookie 的值。

完整的 Set-Cookie 示例

Set-Cookie: username=peter; expires=Thu, 18 Dec 2024 12:00:00UTC; path=/; domain=.example.com; secure; HttpOnly

时间格式必须遵守 RFC 1123 标准, 具体格式样例: Tue, 01 Jan 2030 12:34:56GMT 或者 UTC(推荐)。

关于时间解释

○ Tue: 星期二(星期几的缩写)

○ ,: 逗号分隔符

○ 01: 日期(两位数表示)

○ Jan: 一月(月份的缩写)

○ 2030: 年份(四位数)

○ 12:34:56: 时间(小时、 分钟、 秒)

○ GMT: 格林威治标准时间(时区缩写)

区别:

• 计算方式: GMT 基于地球的自转和公转, 而 UTC 基于原子钟。

• 准确度: 由于 UTC 基于原子钟, 它比基于地球自转的 GMT 更加精确。

在实际使用中, GMT 和 UTC 之间的差别通常很小, 大多数情况下可以互换使用。 但在需要高精度时间计量的场合, 如科学研究、 网络通信等, UTC 是更为准确的选择

我们写好时间:

    std::string GetMonthName(int month){std::vector<std::string> months = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};return months[month];}std::string GetWeekDayName(int day){std::vector<std::string> weekdays = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};return weekdays[day];}std::string ExpireTimeUseRfc1123(int t) // 秒级别的未来UTC时间{time_t timeout = time(nullptr) + t;struct tm *tm = gmtime(&timeout); // 这里不能用localtime,因为localtime是默认带了时区的. gmtime获取的就是UTC统一时间char timebuffer[1024];//时间格式如: expires=Thu, 18 Dec 2024 12:00:00 UTCsnprintf(timebuffer, sizeof(timebuffer), "%s, %02d %s %d %02d:%02d:%02d UTC", GetWeekDayName(tm->tm_wday).c_str(),tm->tm_mday,GetMonthName(tm->tm_mon).c_str(),tm->tm_year+1900,tm->tm_hour,tm->tm_min,tm->tm_sec);return timebuffer;}

在使用带时间的cookie:让cookie1min过期

    std::string ProveCookieTimeOut(){return "Set-Cookie: username=zhangsan; expires=" + ExpireTimeUseRfc1123(60) + ";"; // 让cookie 1min后过期}
        resp.AddHeader(ProveCookieTimeOut()); //测试过期时间的写入

在本地服务器直接测试: 现在cookie就是带时间的了。带的是格林威治时间

在浏览器当中测试:此时的cookie显示的就是一个到期时间了。

但是这里有一个细节:实际上在提交的时候只会提交cookie的主题内容也就是这个参数,时间是没有携带的

给cookie设置上路径

服务器访问资源是从他的web根目录开始,有一个树状结构,path=/则表示:这个cookie在从/开始,用b站来举例就是我的这个cookie在整个b站都有效。

如果path=/a/b;那么就会在浏览器访问制定路径时访问cookie:

    std::string ProvePath(){return "Set-Cookie: username=zhangsan; path=/a/b;";}
        resp.AddHeader(ProvePath()); // 测试路径

因此在访问其他路径时,就不会在添加cookie

在我们使用101.43.132.76:8891ip:端口号来访问的时候,默认是访问根目录的,因此就不会携带cookie

只有当我们在访问指定的资源时,才会携带:

写入多组cookie

这种方法可以吗?直接在一条cookie的一个参数后面再添加,不可以。

    std::string ProvePath(){return "Set-Cookie: username=zhangsan; passwd=123; path=/a/b;";}
        resp.AddHeader(ProvePath());

观察结构,我们可以知道,cookie是以设置的第一个名字来命名的,因此这样写,根本不能知道passwd是啥。

正确写法:

    std::string ProveOtherCookie(){return "Set-Cookie: passwd=1234567890; path=/a/b;";}
        resp.AddHeader(ProvePath());resp.AddHeader(ProveOtherCookie());

这样写就能成功添加:

其他可选属性的解释

○ expires=<date>[要验证]: 设置 Cookie 的过期日期/时间。 如果未指定此属性, 则 Cookie 默认为会话 Cookie, 即当浏览器关闭时过期。

○ path=<some_path>[要验证]: 限制 Cookie 发送到服务器的哪些路径。 默认为设置它的路径。

○ domain=<domain_name>[了解即可]: 指定哪些主机可以接受该 Cookie。 默认为设置它的主机。

○ secure[了解即可]: 仅当使用 HTTPS 协议时才发送 Cookie。 这有助于防止Cookie 在不安全的 HTTP 连接中被截获

○ HttpOnly[了解即可]: 标记 Cookie 为 HttpOnly, 意味着该 Cookie 不能被客户端脚本(如 JavaScript) 访问。 这有助于防止跨站脚本攻击(XSS) 。

单独使用 Cookie, 有什么问题?

• 我们写入的是测试数据, 如果写入的是用户的私密数据呢? 比如, 用户名密码,浏览痕迹等。

• 本质问题在于这些用户私密数据在浏览器(用户端)保存, 非常容易被人盗取, 更重要的是, 除了被盗取, 还有就是用户私密数据也就泄漏了。

Session

定义

与cookie不同的是session是在服务器端维护的

HTTP Session 是服务器用来跟踪用户与服务器交互期间用户状态的机制。 由于 HTTP协议是无状态的(每个请求都是独立的) , 因此服务器需要通过 Session 来记住用户的信息

工作原理

当用户首次访问网站时, 服务器会为用户创建一个唯一的 Session ID, 并通过Cookie(传Session ID) 将其发送到客户端。

客户端在之后的请求中会携带这个 Session ID服务器通过 Session ID 来识别用户, 从而获取用户的会话信息。

服务器通常会将 Session 信息存储在内存、 数据库或缓存中。

通过代码来理解:

路径:

linux-plus-meal/http-cookie-session/session

相比于Cookie,多添加了Session.hpp 

.
├── Comm.hpp
├── HttpProtocol.hpp
├── InetAddr.hpp
├── LockGuard.hpp
├── Log.hpp
├── Main.cc
├── Makefile
├── Session.hpp
├── Socket.hpp
├── TcpServer.hpp
├── Thread.hpp
└── ThreadPool.hpp

Session.hpp,模拟实现session

#pragma once#include <iostream>
#include <string>
#include <memory>
#include <ctime>
#include <unistd.h>
#include <unordered_map>// 用来进行测试说明
class Session
{
public:Session(const std::string &username, const std::string &status):_username(username), _status(status){_create_time = time(nullptr); // 获取时间戳就行了,后面实际需要,就转化就转换一下}~Session(){}
public:std::string _username;std::string _status;uint64_t _create_time;uint64_t _time_out; // 60*5std::string vip; // vipint active; // std::string pos;//当然还可以再加任何其他信息,看你的需求
};using session_ptr = std::shared_ptr<Session>;class SessionManager
{
public:SessionManager(){srand(time(nullptr) ^ getpid());}std::string AddSession(session_ptr s){uint32_t randomid = rand() + time(nullptr); // 随机数+时间戳,实际有形成sessionid的库,比如boost uuid库,或者其他第三方库等std::string sessionid = std::to_string(randomid);_sessions.insert(std::make_pair(sessionid, s));return sessionid;}session_ptr GetSession(const std::string sessionid){if(_sessions.find(sessionid) == _sessions.end()) return nullptr;return _sessions[sessionid];}~SessionManager(){}
private:std::unordered_map<std::string, session_ptr> _sessions;
};

通过分析session代码,可以看出在session类内部,是将用户名、状态、以及session创建时间封装起来的,在SessionManager类当中,就存了一个session id与Session对象的智能指针的映射关系的成员session对象_session。

在SessionManager类当中,还有一个添加session对象的函数AddSession(),sessionid就通过随机数生成的方式来创建。而GetSession就是用来通过客户端传来的sessionid,将session对象返回给服务器。

注意理解解析函数:

 void Parse(){// 解析出来urlstd::stringstream ss(_req_line);ss >> _method >> _url >> _http_version;// 查找cookiestd::string prefix = "Cookie: "; // 写入: Set-Cookie: sessionid=1234 提交: Cookie: sessionid=1234for (auto &line : _req_header){std::string cookie;if (strncmp(line.c_str(), prefix.c_str(), prefix.size()) == 0) // 找到了{cookie = line.substr(prefix.size()); // 截取"Cookie: "之后的就行了_cookies.emplace_back(cookie);break;}}// 查找sessionid// sessionid=1234prefix = "sessionid=";for (const auto &cookie : _cookies){if (strncmp(cookie.c_str(), prefix.c_str(), prefix.size()) == 0){_sessionid = cookie.substr(prefix.size()); // 截取"sessionid="之后的就行了// std::cout << "_sessionid: " << _sessionid << std::endl;}}}

构建了对session的管理的对象: 

  当解析出请求报文之后,根据path,向指定浏览器写入session

在第二次访问时,因为cookie中已经存好了sessionid,因此到服务器的时候解析好之后就已经有了sessionid,就直接使用sessionid获取session对象,再去判断sessionid是否存在sessions哈希表当中,如果不存在就直接return 空串,则这个sessionid已经过期。如果获取成功则打印出用户名。

只要是同一个域,那么id也就相同,用户就是同一个,但是换一个浏览器,就能添加上第二个用户

两个浏览器就能充当两个不同的客户端。

实际会话保持的做法:cookie+session

安全性:

与 Cookie 相似, 由于 Session ID 是在客户端和服务器之间传递的, 因此也存在被窃取的风险。

但是一般虽然 Cookie 被盗取了, 但是用户只泄漏了一个 Session ID, 私密信息暂时没有被泄露的风险。但是也可以模拟通过sessionid来访问服务端。

Session ID 便于服务端进行客户端有效性的管理, 比如异地登录。可以通过 HTTPS 和设置合适的 Cookie 属性(如 HttpOnly 和 Secure) 来增强安全性。

超时和失效:

Session 可以设 超时时间, 当超过这个时间后, Session 会自动失效。服务器也可以主动使 Session 失效, 例如当用户登出时

用途:

用户认证和会话管理

存储用户的临时数据(如购物车内容)

实现分布式系统的会话共享(通过将会话数据存储在共享数据库或缓存中)

总结:

HTTP Cookie 和 Session 都是用于在 Web 应用中跟踪用户状态的机制。 Cookie 是存储在客户端的, 而 Session 是存储在服务器端的。 它们各有优缺点, 通常在实际应用中会结合使用, 以达到最佳的用户体验和安全性。

session相对安全的,但是sessionid可能会被盗取。

通过sessionid可能被冒认,私密信息会被泄露,session是服务器创建,服务器管理的,大师有解决办法:只要让sessionid失效,就能防止被盗取。

因此服务器怎么知道这个client对应的session是非法的呢?

有很多做法,但是要和业务结合(活跃指数、用户登录地点)、来判断是否有安全隐患,再做一些处理措施。

结语:

       随着这篇博客接近尾声,我衷心希望我所分享的内容能为你带来一些启发和帮助。学习和理解的过程往往充满挑战,但正是这些挑战让我们不断成长和进步。我在准备这篇文章时,也深刻体会到了学习与分享的乐趣。    

         在此,我要特别感谢每一位阅读到这里的你。是你的关注和支持,给予了我持续写作和分享的动力。我深知,无论我在某个领域有多少见解,都离不开大家的鼓励与指正。因此,如果你在阅读过程中有任何疑问、建议或是发现了文章中的不足之处,都欢迎你慷慨赐教。

        你的每一条反馈都是我前进路上的宝贵财富。同时,我也非常期待能够得到你的点赞、收藏,关注这将是对我莫大的支持和鼓励。当然,我更期待的是能够持续为你带来有价值的内容。

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

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

相关文章

[ Qt ] | 第一个Qt程序

1. 创建Qt项目 我们打开Qt Create工具&#xff0c;左上角“文件”&#xff0c;新建文件。 --- --- --- --- 这个是我们的APP“走出国门”的时候&#xff0c;要关注的&#xff0c;这里就不说了。 后面这两个直接默认&#xff0c;下一步就行~~。 2. 项目默认内容 下面就是Qt C…

影刀RPA中新增自己的自定义指令

入门到实战明细 1. 影刀RPA自定义指令概述 1.1 定义与作用 影刀RPA的自定义指令是一种强大的功能&#xff0c;旨在提高流程复用率&#xff0c;让用户能够个性化定制指令&#xff0c;实现流程在不同应用之间的相互调用。通过自定义指令&#xff0c;用户可以将常用的、具有独立…

LangChain:重构大语言模型应用开发的范式革命

2022年10月22日,Harrison Chase在GitHub上提交了名为LangChain的开源项目的第一个代码版本。这个看似普通的代码提交,却悄然开启了一场重塑大语言模型(LLM)应用开发范式的技术革命。彼时,距离ChatGPT引爆全球人工智能浪潮尚有一月之遥,但LangChain的诞生已经预示了LLM技术…

区块链+医疗:破解数据共享困局,筑牢隐私安全防线

在医疗健康领域&#xff0c;数据共享与隐私保护一直是一对难以调和的矛盾。一方面&#xff0c;分散在不同机构的医疗数据&#xff08;如电子病历、检查报告、用药记录&#xff09;阻碍了诊疗效率和科研进展&#xff1b;另一方面&#xff0c;患者隐私泄露事件频发&#xff0c;加…

pycharm导入同目录下文件未标红但报错ModuleNotFoundError

此贴仅为记录debug过程&#xff0c;为防后续再次遇见 问题 问题情境 复现文章模型&#xff0c;pycharm项目初次运行 问题描述 在导入同目录下其它文件夹中的python文件时&#xff0c;未标红&#xff0c;但运行时报错ModuleNotFoundError 报错信息 未找到该模块 Traceback …

启发式算法-蚁群算法

蚁群算法是模拟蚂蚁觅食行为的仿生优化算法&#xff0c;原理是信息素的正反馈机制&#xff0c;蚂蚁通过释放信息素来引导同伴找到最短路径。把问题的元素抽象为多条路径&#xff0c;每次迭代时为每只蚂蚁构建一个解决方案&#xff0c;该解决方案对应一条完整的路径&#xff0c;…

Redis 脚本:深入理解与实践指南

Redis 脚本:深入理解与实践指南 引言 Redis 是一款高性能的键值存储数据库,广泛应用于缓存、消息队列、分布式锁等领域。脚本在 Redis 中扮演着至关重要的角色,它允许开发者以编程的方式执行复杂的操作,提高数据处理的效率。本文将深入探讨 Redis 脚本的概念、应用场景、…

Vue3 Echarts 3D立方体柱状图实现教程

文章目录 前言一、实现原理二、series ——type: "pictorialBar" 简介2.1 常用属性 三、代码实战3.1 封装一个echarts通用组件 echarts.vue3.2 实现一个立方体柱状图&#xff08;1&#xff09;首先实现一个基础柱状图&#xff08;2&#xff09;添加立方体棱线&#x…

每天一道面试题@第五天

1.包装类型的缓存机制了解么&#xff1f; 指部分包装类在创建对象时&#xff0c;会将一定范围内的对象缓存起来&#xff0c;当再次使用相同值创建对象时&#xff0c;优先从缓存中获取&#xff0c;而不是重新创建新对象。【提高性能】【节省内存】 列举几个常见的包装类缓存机…

mysql--索引

索引作为一种数据结构&#xff0c;其用途是用于提升检索数据的效率。 分类 普通索引&#xff08;INDEX&#xff09;&#xff1a;索引列值可重复 唯一索引&#xff08;UNIQUE&#xff09;&#xff1a;索引列值必须唯一&#xff0c;可以为NULL 主键索引&#xff08;PRIMARY KEY&a…

王道考研数据结构课后题代码题(2026版)——排序部分

一、前言 本合集以王道考研《数据结构》辅导书&#xff08;2026版&#xff09;课后习题代码题部分为参考依据&#xff0c;给出课后习题代码题的可执行代码的实现&#xff0c;本合集使用编程语言以C/C语言为主&#xff0c;也不限于使用Python和Java语言&#xff0c;本套合计代码…

AVFormatContext 再分析零

随着对于AVFormatContext 各个参数的学习&#xff0c;逐渐可以从 整体架构上 再认识一下 AVFormatContext 了。 还是从解封装的第一步开始。 int avformat_open_input(AVFormatContext **ps, const char *url, ff_const59 AVInputFormat *fmt, AVDictionary **options); 实际上…

uniapp打包apk详细教程

目录 1.打apk包前提条件 2.获取uni-app标识 3.进入dcloud开发者后台 4.开始打包 1.打apk包前提条件 1.在HBuilderX.exe软化中&#xff0c;登录自己的账号 2.在dcloud官网&#xff0c;同样登录自己的账号。没有可以免费注册。 2.获取uni-app标识 获取方法&#xff1a;点…

Vue2 和 Vue3 的核心区别

1. 响应式原理&#xff1a;从「手动挡」到「自动挡」 Vue2&#xff1a; 使用 Object.defineProperty 监听数据变化&#xff0c;但无法检测新增属性和数组索引修改&#xff0c;需要借助 Vue.set。 // Vue2 中修改数组元素不会触发视图更新 this.list[0] 新值; // ❌ 不…

EMMC存储性能测试方法

记于 2022 年 9 月 15 日 EMMC存储性能测试方法 - Wesley’s Blog 参考Android-emmc性能测试 | 一叶知秋进行实践操作 dd 命令 页面缓存 为了测试 emmc 的真实读写性能&#xff0c;我们需要先把页面缓存给清理&#xff1a; echo 1 > /proc/sys/vm/drop_caches console:…

软件管理(安装方式)

1.rpm安装 1.1.rpm介绍 rpm软件包名称: 软件名称 版本号(主版本、次版本、修订号) 操作系统 -----90%的规律 举例:openssh-6.6.1p1-31.el7.x86_64.rpm 数字是版本号:第一位主版本号,第二位次版本号,带横杠的是修订号, el几---操作系统的版本。 #用rpm安装需要考虑如下信…

OnlyOffice Document Server 源码调试指南-ARM和x86双模式安装支持

在ARM64架构下创建的ONLYOFFICE源码调试容器具有显著优势。该容器基于官方Document Server镜像构建&#xff0c;通过集成Git、Python和Node.js等工具链&#xff0c;实现跨平台环境一致性&#xff0c;确保ARM设备的兼容性。容器化隔离消除了依赖冲突&#xff0c;支持快速部署到边…

oracle 数据库查询指定用户下每个表占用空间的大小,倒序显示

oracle 查询指定用户下每个表占用空间的大小&#xff0c;倒序显示 使用场景&#xff1a;数据分析&#xff1b;导出医院正式库到开发环境时&#xff0c;查询出占用表空间高的业务表、导出时排除该表 在Oracle数据库中&#xff0c;要查询指定用户下每个表占用空间的大小并以倒序…

归并排序【逆序对】

目录 归并排序原理 逆序对 归并排序 主要利用分治思想&#xff0c;时间复杂度O(nlogn) 原理 1.对数列不断等长拆分&#xff0c;直到一个数的长度。2.回溯时&#xff0c;按升序合并左右两段。3.重复以上两个过程&#xff0c;直到递归结束。 合并 1.i&#xff0c;j分别指向a的…

AI 与生物技术的融合:开启精准医疗的新纪元

在科技飞速发展的今天&#xff0c;人工智能&#xff08;AI&#xff09;与生物技术的融合正在成为推动医疗领域变革的重要力量。精准医疗作为现代医学的重要发展方向&#xff0c;旨在通过深入了解个体的基因信息、生理特征和生活方式&#xff0c;为患者提供个性化的治疗方案。AI…