This commit is contained in:
2026-02-08 12:35:58 +00:00
commit 78a9cd9b21
313 changed files with 93775 additions and 0 deletions

325
2020/06/06/demoscene.html Normal file
View File

@@ -0,0 +1,325 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- Begin Jekyll SEO tag v2.8.0 -->
<title>关于Demoscene的探索 | Mayx的博客</title>
<meta name="generator" content="Jekyll v3.9.5" />
<meta property="og:title" content="关于Demoscene的探索" />
<meta name="author" content="mayx" />
<meta property="og:locale" content="zh_CN" />
<meta name="description" content="大佬们的领域我们无法步入……" />
<meta property="og:description" content="大佬们的领域我们无法步入……" />
<meta property="og:site_name" content="Mayx的博客" />
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2020-06-06T00:00:00+08:00" />
<meta name="twitter:card" content="summary" />
<meta property="twitter:title" content="关于Demoscene的探索" />
<meta name="google-site-verification" content="huTYdEesm8NaFymixMNqflyCp6Jfvd615j5Wq1i2PHc" />
<meta name="msvalidate.01" content="0ADFCE64B3557DC4DC5F2DC224C5FDDD" />
<meta name="yandex-verification" content="fc0e535abed800be" />
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"BlogPosting","author":{"@type":"Person","name":"mayx"},"dateModified":"2020-06-06T00:00:00+08:00","datePublished":"2020-06-06T00:00:00+08:00","description":"大佬们的领域我们无法步入……","headline":"关于Demoscene的探索","mainEntityOfPage":{"@type":"WebPage","@id":"/2020/06/06/demoscene.html"},"publisher":{"@type":"Organization","logo":{"@type":"ImageObject","url":"https://avatars0.githubusercontent.com/u/17966333"},"name":"mayx"},"url":"/2020/06/06/demoscene.html"}</script>
<!-- End Jekyll SEO tag -->
<link rel="canonical" href="https://mabbs.github.io/2020/06/06/demoscene.html" />
<link type="application/atom+xml" rel="alternate" href="/atom.xml" title="Mayx的博客" />
<link rel="alternate" type="application/rss+xml" title="Mayx的博客(RSS)" href="/rss.xml" />
<link rel="alternate" type="application/json" title="Mayx的博客(JSON Feed)" href="/feed.json" />
<link rel="stylesheet" href="/assets/css/style.css?v=1770554153" />
<!--[if !IE]> -->
<link rel="stylesheet" href="/Live2dHistoire/live2d/css/live2d.css" />
<!-- <![endif]-->
<link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="Mayx的博客" />
<link rel="webmention" href="https://webmention.io/mabbs.github.io/webmention" />
<link rel="pingback" href="https://webmention.io/mabbs.github.io/xmlrpc" />
<link rel="preconnect" href="https://summary.mayx.eu.org" crossorigin="anonymous" />
<link rel="prefetch" href="https://www.blogsclub.org/badge/mabbs.github.io" as="image" />
<link rel="blogroll" type="text/xml" href="/blogroll.opml" />
<link rel="me" href="https://github.com/Mabbs" />
<script src="/assets/js/jquery.min.js"></script>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-ajaxtransport-xdomainrequest/1.0.3/jquery.xdomainrequest.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<script>
var lastUpdated = new Date("Sun, 08 Feb 2026 20:35:53 +0800");
var BlogAPI = "https://summary.mayx.eu.org";
</script>
<script src="/assets/js/main.js"></script>
<!--[if !IE]> -->
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async="async" src="https://www.googletagmanager.com/gtag/js?id=UA-137710294-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-137710294-1');
</script>
<script src="/assets/js/instant.page.js" type="module"></script>
<!-- <![endif]-->
</head>
<body>
<!--[if !IE]> --><noscript><marquee style="top: -15px; position: relative;"><small>发现当前浏览器没有启用JavaScript这不影响你的浏览但可能会有一些功能无法使用……</small></marquee></noscript><!-- <![endif]-->
<!--[if IE]><marquee style="top: -15px; position: relative;"><small>发现当前浏览器为Internet Explorer这不影响你的浏览但可能会有一些功能无法使用……</small></marquee><![endif]-->
<div class="wrapper">
<header class="h-card">
<h1><a class="u-url u-uid p-name" rel="me" href="/">Mayx的博客</a></h1>
<img src="https://avatars0.githubusercontent.com/u/17966333" fetchpriority="high" class="u-photo" alt="Logo" style="width: 90%; max-width: 300px; max-height: 300px;" />
<p class="p-note">Mayx's Home Page</p>
<form action="/search.html">
<input type="text" name="keyword" id="search-input-all" placeholder="Search blog posts.." />&#160;<input type="submit" value="搜索" />
</form>
<br />
<p class="view"><a class="u-url" href="/Mabbs/">About me</a></p>
<ul class="downloads">
<li style="width: 270px; border-right: none;"><a href="/MayxBlog.tgz">Download <strong>TGZ File</strong></a></li>
</ul>
</header>
<section class="h-entry">
<small><time class="date dt-published" datetime="2020-06-06T00:00:00+08:00">6 June 2020</time> - 字数统计1799 - 阅读大约需要6分钟 - Hits: <span id="/2020/06/06/demoscene.html" class="visitors">Loading...</span></small>
<h1 class="p-name">关于Demoscene的探索</h1>
<p class="view">by <a class="p-author h-card" href="//github.com/Mabbs">mayx</a></p>
<div id="outdate" style="display:none;">
<hr /><p>
这是一篇创建于 <span id="outime"></span> 天前的文章,其中的信息可能已经有所发展或是发生改变。
</p>
</div>
<script>
daysold = Math.floor((new Date().getTime() - new Date("Sat, 06 Jun 2020 00:00:00 +0800").getTime()) / (24 * 60 * 60 * 1000));
if (daysold > 90) {
document.getElementById("outdate").style.display = "block";
document.getElementById("outime").innerHTML = daysold;
}
</script>
<hr />
<b>AI摘要</b>
<p id="ai-output">这篇文章讲述了作者对Demoscene这一计算机艺术亚文化的回顾。Demoscene或称演景是用很小的程序如64KiB、92KiB甚至4KiB来渲染出复杂且带音频的视频通常利用计算机硬件如显卡提高效率。它强调了Demoscene作品对数学和编程技巧的要求很高以C++、汇编等语言甚至JS编写。文章提到了一些著名作品和组织如Farbrausch和OMNISCENT以及一个4KiB的名为elevated的作品展示了其技术的精细和创新。作者虽然自认为没有能力参与但仍欣赏这种艺术形式。最后作者推荐了scene.org和js1k.com等网站供读者进一步探索。</p>
<hr />
<ul><li><a href="#前言">前言</a></li><li><a href="#什么是demoscene">什么是Demoscene</a></li><li><a href="#demoscene的实现方式">Demoscene的实现方式</a></li><li><a href="#后记">后记</a></li></ul>
<hr />
<main class="post-content e-content" role="main"><p>大佬们的领域我们无法步入……<!--more--></p>
<h1 id="前言">
<a href="#前言"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 前言
</h1>
<p>最近闲来无事又在回顾自己的历史真是呜呼哀哉……14年左右的我是那么的有探索和研究精神怎么过了几年之后就成Five了呢…… </p><p>
在我过去留下的文件里,我找到了一些比较有意思的东西,比如当时网上传的很火的一个叫做<a href="http://www.theproduct.de/">.the .product</a>的一个64KiB的动画传说它用了外星压缩算法把1个多GiB的东西压缩成了64KiB真是令人感到不可思议还有一个叫做<a href="https://files.scene.org/view/parties/2004/breakpoint04/96kgame/kkrieger-beta.zip">kkrieger</a>的3D游戏同样也仅仅用了92KiB。 </p><p>
这两个作品都来自一个叫做Farbrausch的组织可能是这个组织的宣传做的比较好其他的Demoscene虽然做的也很不错但是并不怎么知名唯有这个组织的Demoscene在网上广为流传……不过也许是因为Breakpoint的Party知名度比较高 </p><p>
除此之外在Windows XP时代喜欢玩批处理的人也一定知道一个叫做<a href="https://files.scene.org/view/parties/1997/mekka97/in4k/snc_omni.zip">OMNISCENT</a>的动画把一串乱七八糟的东西放到debug程序里得出的一个只有4KiB的小程序就能播放出一个看起来好像在一个飞船里的一个3D动画。
以上所说的这些我当时不知道是什么东西。到了现在我才知道这些是一种叫做Demoscene的东西。</p>
<h1 id="什么是demoscene">
<a href="#什么是demoscene"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 什么是Demoscene
</h1>
<p>Demoscene根据百科所说是一种计算机艺术亚文化中文名叫做演景。玩这个的人就喜欢用计算机来渲染出一些看起来很有感觉的带音频的视频。因为这些画面都是直接渲染出来的所以占用的空间也非常的小。 </p><p>
这个道理就和位图和矢量图、波形音乐和MIDI音乐一样程序总比数据占用的空间小所以Demoscene通常来说都是用很小的程序来表现很复杂的场面。不过做过像svg的人应该也知道同一个图像做矢量图的难度要比制作位图的难度要大这也就是为什么Demoscene是只有大佬才会玩的东西。 </p><p>
虽然说这个东西说是计算机文化但是在我看来这个东西就是会写程序的数学家搞的玩意这就和NOI一样荒谬一堆数学题非得要叫个信息学比赛……</p>
<h1 id="demoscene的实现方式">
<a href="#demoscene的实现方式"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> Demoscene的实现方式
</h1>
<p>过去的Demoscene通常都是使用汇编写出来的虽然说汇编写出来的程序应该很小但是它因为过于复杂以至于有些硬件资源它无法很好的利用。 </p><p>
因为Demoscene主要表现的是音乐和视频那么这些事让显卡做的效率自然要比用CPU做的效率高很多。比如说我上面所说的OMNISCENT这个程序完全使用的是CPU的计算资源虽然使用了4KiB看起来很小但是事实上还是浪费了不少的空间。最近我在逛<a href="https://scene.org/">scene.org</a>的时候见到了一个更加厉害的Demoscene名字叫做<a href="https://files.scene.org/view/parties/2009/breakpoint09/in4k/rgba_tbc_elevated.zip">elevated</a>。它用了4KiB表现了一座山的春夏秋冬不仅画面更加精致而且时长也更长。 </p><p>
我看了一下,他们还放出了<a href="https://files.scene.org/view/resources/code/sources/rgba_tbc_elevated_source.zip">源代码</a>看起来是使用C++和汇编写出来的使用了微软的DirectX9来调用显卡。再看其他代码好多东西就只用了一句话来表示比如太阳就只需要一句<code class="language-plaintext highlighter-rouge">"+pow(saturate(mul(e,q[3])),16)*float3(.4,.3,.1)"</code>,云也只有一句<code class="language-plaintext highlighter-rouge">"+.1*f(s+q[3].w*.2,10)"</code>。这样看来难怪整个程序那么小,一个公式就表示了一个模型,这群伪装成程序员的数学家也真是有够强。 </p><p>
除此之外也有一些用数学界常有的复杂3D模型生成公式的比如什么Romanesco Broccoli还有分形之类乱七八糟的东西像这些就超出我的理解范围了 <del>(连线代都搞不懂还搞这个?)</del></p>
<h1 id="后记">
<a href="#后记"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 后记
</h1>
<p>既然Demoscene对数学的要求如此之高对我来说自然是无缘步入了。但是欣赏他们的作品还是挺不错的。 </p><p>
除了上述的一些Demo(Intro)外我还找到了一些比较有意思的比如今年一个叫做Revision的Party里就有一个叫做<a href="https://files.scene.org/view/parties/2020/revision20/pc-4k-intro/synccord_nusanvalden.zip">SyncCord</a>的作品同样是4KiB效果也是非常的不错。 </p><p>
当然也不一定非要局限于4KiB还是64KiB更大的有更多的表现空间就比如07年的一个叫做<a href="https://files.scene.org/view/parties/2007/breakpoint07/demo/fr-041_debris.zip">debris</a>的作品堪称大片大小也仅仅只有177KiB另外这也是Farbrausch的作品。 </p><p>
更多的作品大家可以自己去<a href="https://scene.org/">scene.org</a>这里面有历年各位神仙做的各种各样的Demoscene。 </p><p>
另外除了这些程序之外也还有一些大佬拿JS写的只有1KiB的网页大家可以在<a href="https://js1k.com/">js1k.com</a>里找到当然这些和那些写真正程序的人完全不能比只是觉得1KiB的JS能做出那些东西也感觉很有意思。</p></main>
<small style="display: block">tags: <a rel="category tag" class="p-category" href="/search.html?keyword=Demoscene"><em>Demoscene</em></a> <span style="float: right;"><a href="https://gitlab.com/mayx/mayx.gitlab.io/tree/master/_posts/2020-06-06-demoscene.md">查看原始文件</a></span></small>
<h4 style="border-bottom: 1px solid #e5e5e5;margin: 2em 0 5px;">推荐文章</h4>
<p id="suggest-container">Loading...</p>
<script>
var suggest = $("#suggest-container");
$.get(BlogAPI + "/suggest?id=/2020/06/06/demoscene.html&update=" + lastUpdated.valueOf(), function (data) {
if (data.length) {
getSearchJSON(function (search) {
suggest.empty();
var searchMap = {};
for (var i = 0; i < search.length; i++) {
searchMap[search[i].url] = search[i];
}
var tooltip = $('<div class="content-tooltip"></div>').appendTo('body').hide();
for (var j = 0; j < data.length; j++) {
var item = searchMap[data[j].id];
if (item) {
var link = $('<a href="' + item.url + '">' + item.title + '</a>');
var contentPreview = item.content.substring(0, 100);
if (item.content.length > 100) {
contentPreview += "……";
}
link.hover(
function(e) {
tooltip.text($(this).data('content'))
.css({
top: e.pageY + 10,
left: e.pageX + 10
})
.show();
},
function() {
tooltip.hide();
}
).mousemove(function(e) {
tooltip.css({
top: e.pageY + 10,
left: e.pageX + 10
});
}).data('content', contentPreview);
suggest.append(link);
suggest.append(' - ' + item.date + '<br />');
}
}
});
} else {
suggest.html("暂无推荐文章……");
}
});
</script>
<br />
<div class="pagination">
<span class="prev">
<a href="/2020/05/29/encrypt.html">
上一篇写一个加密传输的Demo
</a>
</span>
<br />
<span class="next">
<a href="/2020/06/13/encrypt.html">
下一篇加密传输Demo V2
</a>
</span>
</div>
<!--[if !IE]> -->
<link rel="stylesheet" href="/assets/css/gitalk.css">
<script src="/assets/js/gitalk.min.js"></script>
<div id="gitalk-container"></div>
<script>
var gitalk = new Gitalk({
clientID: '36557aec4c3cb04f7ac6',
clientSecret: 'ac32993299751cb5a9ba81cf2b171cca65879cdb',
repo: 'mabbs.github.io',
owner: 'Mabbs',
admin: ['Mabbs'],
id: '/2020/06/06/demoscene', // Ensure uniqueness and length less than 50
distractionFreeMode: false, // Facebook-like distraction free mode
proxy: "https://cors-anywhere.mayx.eu.org/?https://github.com/login/oauth/access_token"
})
gitalk.render('gitalk-container')
</script>
<!-- <![endif]-->
</section>
<!--[if !IE]> -->
<div id="landlord" style="left:5px;bottom:0px;">
<div class="message" style="opacity:0"></div>
<canvas id="live2d" width="500" height="560" class="live2d"></canvas>
<div class="live_talk_input_body">
<form id="live_talk_input_form">
<div class="live_talk_input_name_body" >
<input type="checkbox" id="load_this" />
<input type="hidden" id="post_id" value="/2020/06/06/demoscene.html" />
<label for="load_this">
<span style="font-size: 11px; color: #fff;">&#160;想问这篇文章</span>
</label>
</div>
<div class="live_talk_input_text_body">
<input name="talk" type="text" class="live_talk_talk white_input" id="AIuserText" autocomplete="off" placeholder="要和我聊什么呀?" />
<button type="submit" class="live_talk_send_btn" id="talk_send">发送</button>
</div>
</form>
</div>
<input name="live_talk" id="live_talk" value="1" type="hidden" />
<div class="live_ico_box" style="display:none;">
<div class="live_ico_item type_info" id="showInfoBtn"></div>
<div class="live_ico_item type_talk" id="showTalkBtn"></div>
<div class="live_ico_item type_music" id="musicButton"></div>
<div class="live_ico_item type_youdu" id="youduButton"></div>
<div class="live_ico_item type_quit" id="hideButton"></div>
<input name="live_statu_val" id="live_statu_val" value="0" type="hidden" />
<audio src="" style="display:none;" id="live2d_bgm" data-bgm="0" preload="none"></audio>
<input id="duType" value="douqilai" type="hidden" />
</div>
</div>
<div id="open_live2d">召唤伊斯特瓦尔</div>
<!-- <![endif]-->
<footer>
<p>
<small>Made with ❤ by Mayx<br />Last updated at 2026-02-08 20:35:53<br /> 总字数617672 - 文章数179 - <a href="/atom.xml" >Atom</a> - <a href="/README.html" >About</a></small>
</p>
</footer>
</div>
<script src="/assets/js/scale.fix.js"></script>
<!--[if !IE]> -->
<script src="/assets/js/main_new.js"></script>
<script src="/Live2dHistoire/live2d/js/live2d.js"></script>
<script src="/Live2dHistoire/live2d/js/message.js"></script>
<!-- <![endif]-->
</body>
</html>

565
2020/06/13/encrypt.html Normal file
View File

@@ -0,0 +1,565 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- Begin Jekyll SEO tag v2.8.0 -->
<title>加密传输Demo V2 | Mayx的博客</title>
<meta name="generator" content="Jekyll v3.9.5" />
<meta property="og:title" content="加密传输Demo V2" />
<meta name="author" content="mayx" />
<meta property="og:locale" content="zh_CN" />
<meta name="description" content="太业余总感觉不太好啊" />
<meta property="og:description" content="太业余总感觉不太好啊" />
<meta property="og:site_name" content="Mayx的博客" />
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2020-06-13T00:00:00+08:00" />
<meta name="twitter:card" content="summary" />
<meta property="twitter:title" content="加密传输Demo V2" />
<meta name="google-site-verification" content="huTYdEesm8NaFymixMNqflyCp6Jfvd615j5Wq1i2PHc" />
<meta name="msvalidate.01" content="0ADFCE64B3557DC4DC5F2DC224C5FDDD" />
<meta name="yandex-verification" content="fc0e535abed800be" />
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"BlogPosting","author":{"@type":"Person","name":"mayx"},"dateModified":"2020-06-13T00:00:00+08:00","datePublished":"2020-06-13T00:00:00+08:00","description":"太业余总感觉不太好啊","headline":"加密传输Demo V2","mainEntityOfPage":{"@type":"WebPage","@id":"/2020/06/13/encrypt.html"},"publisher":{"@type":"Organization","logo":{"@type":"ImageObject","url":"https://avatars0.githubusercontent.com/u/17966333"},"name":"mayx"},"url":"/2020/06/13/encrypt.html"}</script>
<!-- End Jekyll SEO tag -->
<link rel="canonical" href="https://mabbs.github.io/2020/06/13/encrypt.html" />
<link type="application/atom+xml" rel="alternate" href="/atom.xml" title="Mayx的博客" />
<link rel="alternate" type="application/rss+xml" title="Mayx的博客(RSS)" href="/rss.xml" />
<link rel="alternate" type="application/json" title="Mayx的博客(JSON Feed)" href="/feed.json" />
<link rel="stylesheet" href="/assets/css/style.css?v=1770554153" />
<!--[if !IE]> -->
<link rel="stylesheet" href="/Live2dHistoire/live2d/css/live2d.css" />
<!-- <![endif]-->
<link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="Mayx的博客" />
<link rel="webmention" href="https://webmention.io/mabbs.github.io/webmention" />
<link rel="pingback" href="https://webmention.io/mabbs.github.io/xmlrpc" />
<link rel="preconnect" href="https://summary.mayx.eu.org" crossorigin="anonymous" />
<link rel="prefetch" href="https://www.blogsclub.org/badge/mabbs.github.io" as="image" />
<link rel="blogroll" type="text/xml" href="/blogroll.opml" />
<link rel="me" href="https://github.com/Mabbs" />
<script src="/assets/js/jquery.min.js"></script>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-ajaxtransport-xdomainrequest/1.0.3/jquery.xdomainrequest.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<script>
var lastUpdated = new Date("Sun, 08 Feb 2026 20:35:53 +0800");
var BlogAPI = "https://summary.mayx.eu.org";
</script>
<script src="/assets/js/main.js"></script>
<!--[if !IE]> -->
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async="async" src="https://www.googletagmanager.com/gtag/js?id=UA-137710294-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-137710294-1');
</script>
<script src="/assets/js/instant.page.js" type="module"></script>
<!-- <![endif]-->
</head>
<body>
<!--[if !IE]> --><noscript><marquee style="top: -15px; position: relative;"><small>发现当前浏览器没有启用JavaScript这不影响你的浏览但可能会有一些功能无法使用……</small></marquee></noscript><!-- <![endif]-->
<!--[if IE]><marquee style="top: -15px; position: relative;"><small>发现当前浏览器为Internet Explorer这不影响你的浏览但可能会有一些功能无法使用……</small></marquee><![endif]-->
<div class="wrapper">
<header class="h-card">
<h1><a class="u-url u-uid p-name" rel="me" href="/">Mayx的博客</a></h1>
<img src="https://avatars0.githubusercontent.com/u/17966333" fetchpriority="high" class="u-photo" alt="Logo" style="width: 90%; max-width: 300px; max-height: 300px;" />
<p class="p-note">Mayx's Home Page</p>
<form action="/search.html">
<input type="text" name="keyword" id="search-input-all" placeholder="Search blog posts.." />&#160;<input type="submit" value="搜索" />
</form>
<br />
<p class="view"><a class="u-url" href="/Mabbs/">About me</a></p>
<ul class="downloads">
<li style="width: 270px; border-right: none;"><a href="/MayxBlog.tgz">Download <strong>TGZ File</strong></a></li>
</ul>
</header>
<section class="h-entry">
<small><time class="date dt-published" datetime="2020-06-13T00:00:00+08:00">13 June 2020</time> - 字数统计6457 - 阅读大约需要22分钟 - Hits: <span id="/2020/06/13/encrypt.html" class="visitors">Loading...</span></small>
<h1 class="p-name">加密传输Demo V2</h1>
<p class="view">by <a class="p-author h-card" href="//github.com/Mabbs">mayx</a></p>
<div id="outdate" style="display:none;">
<hr /><p>
这是一篇创建于 <span id="outime"></span> 天前的文章,其中的信息可能已经有所发展或是发生改变。
</p>
</div>
<script>
daysold = Math.floor((new Date().getTime() - new Date("Sat, 13 Jun 2020 00:00:00 +0800").getTime()) / (24 * 60 * 60 * 1000));
if (daysold > 90) {
document.getElementById("outdate").style.display = "block";
document.getElementById("outime").innerHTML = daysold;
}
</script>
<hr />
<b>AI摘要</b>
<p id="ai-output">这篇文章描述了一个加密传输Demo的升级版本原作者在上月制作了一个简单的单向加密通信Demo但觉得其业余且安全性不足。因此作者决定改进它实现完整的握手过程以确保双向通信并提高防中间人攻击的能力。实现方法是通过RSA加密一个随机数作为AES密钥密钥在连接建立后保持不变。作者还增加了防止冲突的机制并在Demo中加入了简单的登录系统允许自动化操作。代码展示了通信过程中的密钥交换、数据加密和解密的实现。</p>
<hr />
<ul><li><a href="#前言">前言</a></li><li><a href="#实现思路">实现思路</a></li><li><a href="#代码">代码</a><ul><li><a href="#serverpy">server.py</a></li><li><a href="#clientpy">client.py</a></li></ul></li><li><a href="#后记">后记</a></li></ul>
<hr />
<main class="post-content e-content" role="main"><p>太业余总感觉不太好啊<!--more--></p>
<h1 id="前言">
<a href="#前言"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 前言
</h1>
<p>在上个月我写了一个<a href="/2020/05/29/encrypt.html">加密传输的Demo</a>,相当的业余,这个东西只能做到从客户端向服务端的单向传输,而且因为只有一次请求,所以中间人攻击也非常的容易。 </p><p>
虽然我觉得那个应该足够我完成作业了,但是我想了想,太业余总显得我很菜 <del>(难道不是吗?)</del> ,所以我打算还是努力一下把完整的握手也做出来吧。</p>
<h1 id="实现思路">
<a href="#实现思路"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 实现思路
</h1>
<p>和上次差不多同样我打算通过RSA加密一个随机数作为AES的密钥但是和上次不同这次的这个密钥将在通信建立之后密钥就不再变化传入传出都是这个密钥。 </p><p>
之前觉得握手阶段可能很麻烦,不过我画了一下图稍微理了理思路发现其实也没多复杂,也就是客户端生成密钥然后加密传输过来让服务端保存,完成之后之间的传输只要传被加密的数据就行了。这样我觉得应该也能起到一定的防止中间人攻击的作用吧…… </p><p>
不过我只用了一个文件作为传输的管道,为了避免冲突,我在每次写入数据的时候也都标明了数据的来源,这样就不会因为自己刚发完然后自己又重新接收自己发的东西了。 </p><p>
另外老师希望我的Demo有个简单的应用所以我又另外加了一个极其简单的登录系统在里面这样我就不用手动操作服务端了。</p>
<h1 id="代码">
<a href="#代码"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 代码
</h1>
<h2 id="serverpy">
<a href="#serverpy"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> server.py
</h2>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># -*- coding: utf-8 -*-
</span><span class="k">print</span><span class="p">(</span><span class="s">"加密通道服务端演示开始"</span><span class="p">)</span>
<span class="kn">from</span> <span class="nn">Crypto.PublicKey</span> <span class="kn">import</span> <span class="n">RSA</span>
<span class="kn">from</span> <span class="nn">Crypto.Cipher</span> <span class="kn">import</span> <span class="n">PKCS1_v1_5</span>
<span class="kn">from</span> <span class="nn">Crypto.Cipher</span> <span class="kn">import</span> <span class="n">AES</span>
<span class="kn">import</span> <span class="nn">base64</span>
<span class="kn">import</span> <span class="nn">hashlib</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="n">private_key</span> <span class="o">=</span> <span class="s">"""-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDfEQ82qUrto7h4BL3TsA/DFXSdM44cbeY4kPccD7gLGhaZRClz
YKIh5zYdfjBGF+0HXfMa1u9b7GNs2AjVIsx8Kx0QLnMfmtkmGWGhOXz/9IDLKJOx
0weKv61gysKItgzVKn2mbLool4R/PQBc3AjDyHw+io1KpVz+3kRTaGs1fQIDAQAB
AoGAWB4kFWLA/6k6OOcemd4mC9mQ7HyuOdrMJDJX+5TWDkSrArajbTmSMrRkczgj
F71h3BQn8cVQXs695ARfUNrjTbi2Y0LjN7ScK7ExzTLdoMEFw5JsHggJZ0zBQY6w
mwOdGfqzA6tZPXgkn+jqEha+CD6GrwnTM1oDGJC/aKG2OmECQQDkO9IhUhFc/PSU
0zvGE6AOcqk5wlOuvMg+oAFHJHJZ9XW7+X/Nx0ZoVDFq/cZQj+46t+fiwUwhdW7l
IfCvNGKFAkEA+jRQmWGKrbf1ns4S0SezJvysd5O6otRGJXr+Ex2uDhc39ZTeUsyg
kjrLhp8STLMOmql+8g5fghct17EuCX1EmQJBAJz9BNnEkIrst/OSpH/nyeWGOx6u
q077LaXd+2MLD9kO/O/Se3V5B9YFa4STkJCjoBMloswXd51gIGpdgSeSmd0CQQCL
PrwwcGmWfo+ynqs4PajlpK9zKQMwhYS4bTejedwZOXDKOtx0Ji+i0hfcxwCPMQOK
rZPZsIgUxUOdC508aLvZAkBDkHxunCzDm0w4DdTUN7S9YSpVvQEjK/xUQiWaKV12
8QgskhU2DNdYK2NxifnWrKtx3uQmqMxX5aLuJZ4493yr
-----END RSA PRIVATE KEY-----"""</span>
<span class="c1"># 公钥解密
</span><span class="k">def</span> <span class="nf">rsa_decode</span><span class="p">(</span><span class="n">cipher_text</span><span class="p">,</span> <span class="n">private_key</span><span class="p">):</span>
<span class="n">rsakey</span> <span class="o">=</span> <span class="n">RSA</span><span class="p">.</span><span class="n">importKey</span><span class="p">(</span><span class="n">private_key</span><span class="p">)</span> <span class="c1"># 导入读取到的私钥
</span> <span class="n">cipher</span> <span class="o">=</span> <span class="n">PKCS1_v1_5</span><span class="p">.</span><span class="n">new</span><span class="p">(</span><span class="n">rsakey</span><span class="p">)</span> <span class="c1"># 生成对象
</span> <span class="c1"># 将密文解密成明文返回的是一个bytes类型数据需要自己转换成str
</span> <span class="n">text</span> <span class="o">=</span> <span class="n">cipher</span><span class="p">.</span><span class="n">decrypt</span><span class="p">(</span><span class="n">base64</span><span class="p">.</span><span class="n">b64decode</span><span class="p">(</span><span class="n">cipher_text</span><span class="p">),</span> <span class="s">"ERROR"</span><span class="p">)</span>
<span class="k">return</span> <span class="n">text</span><span class="p">.</span><span class="n">decode</span><span class="p">()</span>
<span class="k">class</span> <span class="nc">PrpCrypt</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span>
<span class="bp">self</span><span class="p">.</span><span class="n">key</span> <span class="o">=</span> <span class="n">key</span><span class="p">.</span><span class="n">encode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">)</span>
<span class="bp">self</span><span class="p">.</span><span class="n">mode</span> <span class="o">=</span> <span class="n">AES</span><span class="p">.</span><span class="n">MODE_CBC</span>
<span class="k">def</span> <span class="nf">encrypt</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">text</span><span class="p">):</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">text</span><span class="p">.</span><span class="n">encode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">)</span>
<span class="n">cryptor</span> <span class="o">=</span> <span class="n">AES</span><span class="p">.</span><span class="n">new</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">key</span><span class="p">,</span> <span class="bp">self</span><span class="p">.</span><span class="n">mode</span><span class="p">,</span> <span class="sa">b</span><span class="s">'0000000000000000'</span><span class="p">)</span>
<span class="c1"># 这里密钥key 长度必须为16AES-128,
</span> <span class="c1"># 24AES-192,或者32 AES-256Bytes 长度
</span> <span class="c1"># 目前AES-128 足够目前使用
</span> <span class="n">length</span> <span class="o">=</span> <span class="mi">16</span>
<span class="n">count</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
<span class="k">if</span> <span class="n">count</span> <span class="o">&lt;</span> <span class="n">length</span><span class="p">:</span>
<span class="n">add</span> <span class="o">=</span> <span class="p">(</span><span class="n">length</span> <span class="o">-</span> <span class="n">count</span><span class="p">)</span>
<span class="c1"># \0 backspace
</span> <span class="c1"># text = text + ('\0' * add)
</span> <span class="n">text</span> <span class="o">=</span> <span class="n">text</span> <span class="o">+</span> <span class="p">(</span><span class="s">'</span><span class="se">\0</span><span class="s">'</span> <span class="o">*</span> <span class="n">add</span><span class="p">).</span><span class="n">encode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">count</span> <span class="o">&gt;</span> <span class="n">length</span><span class="p">:</span>
<span class="n">add</span> <span class="o">=</span> <span class="p">(</span><span class="n">length</span> <span class="o">-</span> <span class="p">(</span><span class="n">count</span> <span class="o">%</span> <span class="n">length</span><span class="p">))</span>
<span class="c1"># text = text + ('\0' * add)
</span> <span class="n">text</span> <span class="o">=</span> <span class="n">text</span> <span class="o">+</span> <span class="p">(</span><span class="s">'</span><span class="se">\0</span><span class="s">'</span> <span class="o">*</span> <span class="n">add</span><span class="p">).</span><span class="n">encode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">)</span>
<span class="bp">self</span><span class="p">.</span><span class="n">ciphertext</span> <span class="o">=</span> <span class="n">cryptor</span><span class="p">.</span><span class="n">encrypt</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
<span class="c1"># 因为AES加密时候得到的字符串不一定是ascii字符集的输出到终端或者保存时候可能存在问题
</span> <span class="c1"># 所以这里统一把加密后的字符串转化为16进制字符串
</span> <span class="k">return</span> <span class="n">base64</span><span class="p">.</span><span class="n">b64encode</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">ciphertext</span><span class="p">)</span>
<span class="c1"># 解密后去掉补足的空格用strip() 去掉
</span> <span class="k">def</span> <span class="nf">decrypt</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">text</span><span class="p">):</span>
<span class="n">cryptor</span> <span class="o">=</span> <span class="n">AES</span><span class="p">.</span><span class="n">new</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">key</span><span class="p">,</span> <span class="bp">self</span><span class="p">.</span><span class="n">mode</span><span class="p">,</span> <span class="sa">b</span><span class="s">'0000000000000000'</span><span class="p">)</span>
<span class="n">plain_text</span> <span class="o">=</span> <span class="n">cryptor</span><span class="p">.</span><span class="n">decrypt</span><span class="p">(</span><span class="n">base64</span><span class="p">.</span><span class="n">b64decode</span><span class="p">(</span><span class="n">text</span><span class="p">))</span>
<span class="c1"># return plain_text.rstrip('\0')
</span> <span class="k">return</span> <span class="nb">bytes</span><span class="p">.</span><span class="n">decode</span><span class="p">(</span><span class="n">plain_text</span><span class="p">).</span><span class="n">rstrip</span><span class="p">(</span><span class="s">'</span><span class="se">\0</span><span class="s">'</span><span class="p">)</span>
<span class="c1">#初始化pipe
</span><span class="nb">file</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">'pipe.txt'</span><span class="p">,</span><span class="s">'w'</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">""</span><span class="p">,</span><span class="nb">file</span> <span class="o">=</span> <span class="nb">file</span><span class="p">)</span>
<span class="nb">file</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
<span class="c1">#协商密钥
</span><span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
<span class="n">pipe</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">"pipe.txt"</span><span class="p">,</span> <span class="n">mode</span><span class="o">=</span><span class="s">'r'</span><span class="p">)</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">pipe</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">data</span> <span class="o">==</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">:</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="n">loads</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="n">pipe</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">break</span>
<span class="n">pipe</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="nb">file</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">'pipe.txt'</span><span class="p">,</span><span class="s">'w'</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">""</span><span class="p">,</span><span class="nb">file</span> <span class="o">=</span> <span class="nb">file</span><span class="p">)</span>
<span class="nb">file</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">key</span> <span class="o">=</span> <span class="n">rsa_decode</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="s">"key"</span><span class="p">],</span> <span class="n">private_key</span><span class="p">)</span>
<span class="n">akey</span> <span class="o">=</span> <span class="n">PrpCrypt</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"成功获取密钥"</span><span class="p">,</span><span class="n">key</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"已建立连接"</span><span class="p">)</span>
<span class="n">userInfo</span><span class="o">=</span><span class="p">{</span><span class="s">"Name"</span><span class="p">:</span><span class="s">"Mayx"</span><span class="p">,</span><span class="s">"Passwd"</span><span class="p">:</span><span class="s">'25d55ad283aa400af464c76d713c07ad'</span><span class="p">,</span><span class="s">"Book"</span><span class="p">:</span><span class="s">"《会说话就多说点》,《在哪里能买到您的著作》"</span><span class="p">}</span>
<span class="c1">#处理阶段
#Waiting for Quest
</span><span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
<span class="n">pipe</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">"pipe.txt"</span><span class="p">,</span> <span class="n">mode</span><span class="o">=</span><span class="s">'r'</span><span class="p">)</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">pipe</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">data</span> <span class="o">==</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">:</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="n">loads</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="k">if</span> <span class="n">data</span><span class="p">[</span><span class="s">"from"</span><span class="p">]</span> <span class="o">==</span> <span class="s">"Client"</span><span class="p">:</span>
<span class="n">pipe</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">break</span>
<span class="n">pipe</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"已收到请求"</span><span class="p">)</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="n">loads</span><span class="p">(</span><span class="n">akey</span><span class="p">.</span><span class="n">decrypt</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="s">"data"</span><span class="p">]))</span>
<span class="k">if</span> <span class="n">data</span><span class="p">[</span><span class="s">"name"</span><span class="p">]</span> <span class="o">==</span> <span class="n">userInfo</span><span class="p">[</span><span class="s">"Name"</span><span class="p">]</span> <span class="ow">and</span> <span class="n">data</span><span class="p">[</span><span class="s">"pwd"</span><span class="p">]</span> <span class="o">==</span> <span class="n">userInfo</span><span class="p">[</span><span class="s">"Passwd"</span><span class="p">]:</span>
<span class="nb">file</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">'pipe.txt'</span><span class="p">,</span><span class="s">'w'</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">json</span><span class="p">.</span><span class="n">dumps</span><span class="p">({</span><span class="s">"from"</span><span class="p">:</span><span class="s">"Server"</span><span class="p">,</span><span class="s">"data"</span><span class="p">:</span><span class="n">akey</span><span class="p">.</span><span class="n">encrypt</span><span class="p">(</span><span class="s">"登录成功,您的书单如下:"</span><span class="o">+</span><span class="n">userInfo</span><span class="p">[</span><span class="s">"Book"</span><span class="p">]).</span><span class="n">decode</span><span class="p">(</span><span class="s">"utf-8"</span><span class="p">)}),</span><span class="nb">file</span> <span class="o">=</span> <span class="nb">file</span><span class="p">)</span>
<span class="nb">file</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">else</span><span class="p">:</span>
<span class="nb">file</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">'pipe.txt'</span><span class="p">,</span><span class="s">'w'</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">json</span><span class="p">.</span><span class="n">dumps</span><span class="p">({</span><span class="s">"from"</span><span class="p">:</span><span class="s">"Server"</span><span class="p">,</span><span class="s">"data"</span><span class="p">:</span><span class="n">akey</span><span class="p">.</span><span class="n">encrypt</span><span class="p">(</span><span class="s">"登录失败"</span><span class="p">).</span><span class="n">decode</span><span class="p">(</span><span class="s">"utf-8"</span><span class="p">)}),</span><span class="nb">file</span> <span class="o">=</span> <span class="nb">file</span><span class="p">)</span>
<span class="nb">file</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">print</span><span class="p">(</span><span class="s">"请求已回应"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"加密通道服务端演示结束"</span><span class="p">)</span>
</code></pre></div></div>
<h2 id="clientpy">
<a href="#clientpy"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> client.py
</h2>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># -*- coding: utf-8 -*-
</span><span class="k">print</span><span class="p">(</span><span class="s">"加密通道客户端演示开始"</span><span class="p">)</span>
<span class="kn">import</span> <span class="nn">random</span>
<span class="kn">from</span> <span class="nn">Crypto.PublicKey</span> <span class="kn">import</span> <span class="n">RSA</span>
<span class="kn">from</span> <span class="nn">Crypto.Cipher</span> <span class="kn">import</span> <span class="n">PKCS1_v1_5</span>
<span class="kn">from</span> <span class="nn">Crypto.Cipher</span> <span class="kn">import</span> <span class="n">AES</span>
<span class="kn">import</span> <span class="nn">base64</span>
<span class="kn">import</span> <span class="nn">hashlib</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="n">public_key</span> <span class="o">=</span> <span class="s">"""-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfEQ82qUrto7h4BL3TsA/DFXSd
M44cbeY4kPccD7gLGhaZRClzYKIh5zYdfjBGF+0HXfMa1u9b7GNs2AjVIsx8Kx0Q
LnMfmtkmGWGhOXz/9IDLKJOx0weKv61gysKItgzVKn2mbLool4R/PQBc3AjDyHw+
io1KpVz+3kRTaGs1fQIDAQAB
-----END PUBLIC KEY-----
"""</span>
<span class="c1"># 公钥加密
</span><span class="k">def</span> <span class="nf">rsa_encode</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">public_key</span><span class="p">):</span>
<span class="n">rsakey</span> <span class="o">=</span> <span class="n">RSA</span><span class="p">.</span><span class="n">importKey</span><span class="p">(</span><span class="n">public_key</span><span class="p">)</span> <span class="c1"># 导入读取到的公钥
</span> <span class="n">cipher</span> <span class="o">=</span> <span class="n">PKCS1_v1_5</span><span class="p">.</span><span class="n">new</span><span class="p">(</span><span class="n">rsakey</span><span class="p">)</span> <span class="c1"># 生成对象
</span> <span class="c1"># 通过生成的对象加密message明文注意在python3中加密的数据必须是bytes类型的数据不能是str类型的数据
</span> <span class="n">cipher_text</span> <span class="o">=</span> <span class="n">base64</span><span class="p">.</span><span class="n">b64encode</span><span class="p">(</span><span class="n">cipher</span><span class="p">.</span><span class="n">encrypt</span><span class="p">(</span><span class="n">message</span><span class="p">.</span><span class="n">encode</span><span class="p">(</span><span class="n">encoding</span><span class="o">=</span><span class="s">"utf-8"</span><span class="p">)))</span>
<span class="c1"># 公钥每次加密的结果不一样跟对数据的padding填充有关
</span> <span class="k">return</span> <span class="n">cipher_text</span><span class="p">.</span><span class="n">decode</span><span class="p">()</span>
<span class="k">class</span> <span class="nc">PrpCrypt</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span>
<span class="bp">self</span><span class="p">.</span><span class="n">key</span> <span class="o">=</span> <span class="n">key</span><span class="p">.</span><span class="n">encode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">)</span>
<span class="bp">self</span><span class="p">.</span><span class="n">mode</span> <span class="o">=</span> <span class="n">AES</span><span class="p">.</span><span class="n">MODE_CBC</span>
<span class="c1"># 加密函数如果text不足16位就用空格补足为16位
</span> <span class="c1"># 如果大于16当时不是16的倍数那就补足为16的倍数。
</span> <span class="k">def</span> <span class="nf">encrypt</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">text</span><span class="p">):</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">text</span><span class="p">.</span><span class="n">encode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">)</span>
<span class="n">cryptor</span> <span class="o">=</span> <span class="n">AES</span><span class="p">.</span><span class="n">new</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">key</span><span class="p">,</span> <span class="bp">self</span><span class="p">.</span><span class="n">mode</span><span class="p">,</span> <span class="sa">b</span><span class="s">'0000000000000000'</span><span class="p">)</span>
<span class="c1"># 这里密钥key 长度必须为16AES-128,
</span> <span class="c1"># 24AES-192,或者32 AES-256Bytes 长度
</span> <span class="c1"># 目前AES-128 足够目前使用
</span> <span class="n">length</span> <span class="o">=</span> <span class="mi">16</span>
<span class="n">count</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
<span class="k">if</span> <span class="n">count</span> <span class="o">&lt;</span> <span class="n">length</span><span class="p">:</span>
<span class="n">add</span> <span class="o">=</span> <span class="p">(</span><span class="n">length</span> <span class="o">-</span> <span class="n">count</span><span class="p">)</span>
<span class="c1"># \0 backspace
</span> <span class="c1"># text = text + ('\0' * add)
</span> <span class="n">text</span> <span class="o">=</span> <span class="n">text</span> <span class="o">+</span> <span class="p">(</span><span class="s">'</span><span class="se">\0</span><span class="s">'</span> <span class="o">*</span> <span class="n">add</span><span class="p">).</span><span class="n">encode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">count</span> <span class="o">&gt;</span> <span class="n">length</span><span class="p">:</span>
<span class="n">add</span> <span class="o">=</span> <span class="p">(</span><span class="n">length</span> <span class="o">-</span> <span class="p">(</span><span class="n">count</span> <span class="o">%</span> <span class="n">length</span><span class="p">))</span>
<span class="c1"># text = text + ('\0' * add)
</span> <span class="n">text</span> <span class="o">=</span> <span class="n">text</span> <span class="o">+</span> <span class="p">(</span><span class="s">'</span><span class="se">\0</span><span class="s">'</span> <span class="o">*</span> <span class="n">add</span><span class="p">).</span><span class="n">encode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">)</span>
<span class="bp">self</span><span class="p">.</span><span class="n">ciphertext</span> <span class="o">=</span> <span class="n">cryptor</span><span class="p">.</span><span class="n">encrypt</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
<span class="c1"># 因为AES加密时候得到的字符串不一定是ascii字符集的输出到终端或者保存时候可能存在问题
</span> <span class="c1"># 所以这里统一把加密后的字符串转化为16进制字符串
</span> <span class="k">return</span> <span class="n">base64</span><span class="p">.</span><span class="n">b64encode</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">ciphertext</span><span class="p">)</span>
<span class="c1"># 解密后去掉补足的空格用strip() 去掉
</span> <span class="k">def</span> <span class="nf">decrypt</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">text</span><span class="p">):</span>
<span class="n">cryptor</span> <span class="o">=</span> <span class="n">AES</span><span class="p">.</span><span class="n">new</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">key</span><span class="p">,</span> <span class="bp">self</span><span class="p">.</span><span class="n">mode</span><span class="p">,</span> <span class="sa">b</span><span class="s">'0000000000000000'</span><span class="p">)</span>
<span class="n">plain_text</span> <span class="o">=</span> <span class="n">cryptor</span><span class="p">.</span><span class="n">decrypt</span><span class="p">(</span><span class="n">base64</span><span class="p">.</span><span class="n">b64decode</span><span class="p">(</span><span class="n">text</span><span class="p">))</span>
<span class="c1"># return plain_text.rstrip('\0')
</span> <span class="k">return</span> <span class="nb">bytes</span><span class="p">.</span><span class="n">decode</span><span class="p">(</span><span class="n">plain_text</span><span class="p">).</span><span class="n">rstrip</span><span class="p">(</span><span class="s">'</span><span class="se">\0</span><span class="s">'</span><span class="p">)</span>
<span class="c1">#初始化阶段
</span><span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">pipe</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">"pipe.txt"</span><span class="p">,</span> <span class="n">mode</span><span class="o">=</span><span class="s">'r'</span><span class="p">)</span>
<span class="k">except</span><span class="p">:</span>
<span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">break</span>
<span class="n">pipe</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
<span class="c1">#协商密钥
</span><span class="n">key</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">random</span><span class="p">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">1000000000000000</span><span class="p">,</span><span class="mi">9999999999999999</span><span class="p">))</span>
<span class="n">akey</span> <span class="o">=</span> <span class="n">PrpCrypt</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
<span class="n">cipher</span> <span class="o">=</span> <span class="n">rsa_encode</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">public_key</span><span class="p">)</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="n">dumps</span><span class="p">({</span><span class="s">"key"</span><span class="p">:</span><span class="n">cipher</span><span class="p">})</span>
<span class="nb">file</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">'pipe.txt'</span><span class="p">,</span><span class="s">'w'</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">data</span><span class="p">,</span><span class="nb">file</span> <span class="o">=</span> <span class="nb">file</span><span class="p">)</span>
<span class="nb">file</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
<span class="n">pipe</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">"pipe.txt"</span><span class="p">,</span> <span class="n">mode</span><span class="o">=</span><span class="s">'r'</span><span class="p">)</span>
<span class="k">if</span> <span class="n">pipe</span><span class="p">.</span><span class="n">read</span><span class="p">()</span> <span class="o">==</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">:</span>
<span class="n">pipe</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">break</span>
<span class="n">pipe</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"成功发送密钥"</span><span class="p">,</span><span class="n">key</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"已建立连接"</span><span class="p">)</span>
<span class="c1">#处理阶段
#Single Quest
</span><span class="n">name</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s">"请输入用户名:"</span><span class="p">)</span>
<span class="n">pwd</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s">"请输入密码:"</span><span class="p">)</span>
<span class="nb">hash</span> <span class="o">=</span> <span class="n">hashlib</span><span class="p">.</span><span class="n">md5</span><span class="p">(</span><span class="n">pwd</span><span class="p">.</span><span class="n">encode</span><span class="p">(</span><span class="n">encoding</span><span class="o">=</span><span class="s">'UTF-8'</span><span class="p">)).</span><span class="n">hexdigest</span><span class="p">()</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="n">dumps</span><span class="p">({</span><span class="s">"from"</span><span class="p">:</span><span class="s">"Client"</span><span class="p">,</span><span class="s">"data"</span><span class="p">:</span><span class="n">akey</span><span class="p">.</span><span class="n">encrypt</span><span class="p">(</span><span class="n">json</span><span class="p">.</span><span class="n">dumps</span><span class="p">({</span><span class="s">"name"</span><span class="p">:</span><span class="n">name</span><span class="p">,</span><span class="s">"pwd"</span><span class="p">:</span><span class="nb">hash</span><span class="p">})).</span><span class="n">decode</span><span class="p">(</span><span class="s">"utf-8"</span><span class="p">)})</span>
<span class="nb">file</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">'pipe.txt'</span><span class="p">,</span><span class="s">'w'</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">data</span><span class="p">,</span><span class="nb">file</span> <span class="o">=</span> <span class="nb">file</span><span class="p">)</span>
<span class="nb">file</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">print</span><span class="p">(</span><span class="s">"已发出,等待回应"</span><span class="p">)</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
<span class="n">pipe</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">"pipe.txt"</span><span class="p">,</span> <span class="n">mode</span><span class="o">=</span><span class="s">'r'</span><span class="p">)</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">pipe</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">data</span> <span class="o">==</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">:</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="n">loads</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="k">if</span> <span class="n">data</span><span class="p">[</span><span class="s">"from"</span><span class="p">]</span> <span class="o">==</span> <span class="s">"Server"</span><span class="p">:</span>
<span class="n">pipe</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">break</span>
<span class="n">pipe</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"已收到回应"</span><span class="p">)</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">akey</span><span class="p">.</span><span class="n">decrypt</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="s">"data"</span><span class="p">])</span>
<span class="k">print</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"加密通道客户端演示结束"</span><span class="p">)</span>
</code></pre></div></div>
<h1 id="后记">
<a href="#后记"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 后记
</h1>
<p>关于SSL/TLS的具体内容我也没有好好看一遍我打算回头有时间仔细看一看然后再回来看这个代码是有多么的糟糕🤪。</p></main>
<small style="display: block">tags: <a rel="category tag" class="p-category" href="/search.html?keyword=%E5%8A%A0%E5%AF%86"><em>加密</em></a> - <a rel="category tag" class="p-category" href="/search.html?keyword=Demo"><em>Demo</em></a> <span style="float: right;"><a href="https://gitlab.com/mayx/mayx.gitlab.io/tree/master/_posts/2020-06-13-encrypt.md">查看原始文件</a></span></small>
<h4 style="border-bottom: 1px solid #e5e5e5;margin: 2em 0 5px;">推荐文章</h4>
<p id="suggest-container">Loading...</p>
<script>
var suggest = $("#suggest-container");
$.get(BlogAPI + "/suggest?id=/2020/06/13/encrypt.html&update=" + lastUpdated.valueOf(), function (data) {
if (data.length) {
getSearchJSON(function (search) {
suggest.empty();
var searchMap = {};
for (var i = 0; i < search.length; i++) {
searchMap[search[i].url] = search[i];
}
var tooltip = $('<div class="content-tooltip"></div>').appendTo('body').hide();
for (var j = 0; j < data.length; j++) {
var item = searchMap[data[j].id];
if (item) {
var link = $('<a href="' + item.url + '">' + item.title + '</a>');
var contentPreview = item.content.substring(0, 100);
if (item.content.length > 100) {
contentPreview += "……";
}
link.hover(
function(e) {
tooltip.text($(this).data('content'))
.css({
top: e.pageY + 10,
left: e.pageX + 10
})
.show();
},
function() {
tooltip.hide();
}
).mousemove(function(e) {
tooltip.css({
top: e.pageY + 10,
left: e.pageX + 10
});
}).data('content', contentPreview);
suggest.append(link);
suggest.append(' - ' + item.date + '<br />');
}
}
});
} else {
suggest.html("暂无推荐文章……");
}
});
</script>
<br />
<div class="pagination">
<span class="prev">
<a href="/2020/06/06/demoscene.html">
上一篇关于Demoscene的探索
</a>
</span>
<br />
<span class="next">
<a href="/2020/06/17/backup.html">
下一篇:论备份的重要性
</a>
</span>
</div>
<!--[if !IE]> -->
<link rel="stylesheet" href="/assets/css/gitalk.css">
<script src="/assets/js/gitalk.min.js"></script>
<div id="gitalk-container"></div>
<script>
var gitalk = new Gitalk({
clientID: '36557aec4c3cb04f7ac6',
clientSecret: 'ac32993299751cb5a9ba81cf2b171cca65879cdb',
repo: 'mabbs.github.io',
owner: 'Mabbs',
admin: ['Mabbs'],
id: '/2020/06/13/encrypt', // Ensure uniqueness and length less than 50
distractionFreeMode: false, // Facebook-like distraction free mode
proxy: "https://cors-anywhere.mayx.eu.org/?https://github.com/login/oauth/access_token"
})
gitalk.render('gitalk-container')
</script>
<!-- <![endif]-->
</section>
<!--[if !IE]> -->
<div id="landlord" style="left:5px;bottom:0px;">
<div class="message" style="opacity:0"></div>
<canvas id="live2d" width="500" height="560" class="live2d"></canvas>
<div class="live_talk_input_body">
<form id="live_talk_input_form">
<div class="live_talk_input_name_body" >
<input type="checkbox" id="load_this" />
<input type="hidden" id="post_id" value="/2020/06/13/encrypt.html" />
<label for="load_this">
<span style="font-size: 11px; color: #fff;">&#160;想问这篇文章</span>
</label>
</div>
<div class="live_talk_input_text_body">
<input name="talk" type="text" class="live_talk_talk white_input" id="AIuserText" autocomplete="off" placeholder="要和我聊什么呀?" />
<button type="submit" class="live_talk_send_btn" id="talk_send">发送</button>
</div>
</form>
</div>
<input name="live_talk" id="live_talk" value="1" type="hidden" />
<div class="live_ico_box" style="display:none;">
<div class="live_ico_item type_info" id="showInfoBtn"></div>
<div class="live_ico_item type_talk" id="showTalkBtn"></div>
<div class="live_ico_item type_music" id="musicButton"></div>
<div class="live_ico_item type_youdu" id="youduButton"></div>
<div class="live_ico_item type_quit" id="hideButton"></div>
<input name="live_statu_val" id="live_statu_val" value="0" type="hidden" />
<audio src="" style="display:none;" id="live2d_bgm" data-bgm="0" preload="none"></audio>
<input id="duType" value="douqilai" type="hidden" />
</div>
</div>
<div id="open_live2d">召唤伊斯特瓦尔</div>
<!-- <![endif]-->
<footer>
<p>
<small>Made with ❤ by Mayx<br />Last updated at 2026-02-08 20:35:53<br /> 总字数617672 - 文章数179 - <a href="/atom.xml" >Atom</a> - <a href="/README.html" >About</a></small>
</p>
</footer>
</div>
<script src="/assets/js/scale.fix.js"></script>
<!--[if !IE]> -->
<script src="/assets/js/main_new.js"></script>
<script src="/Live2dHistoire/live2d/js/live2d.js"></script>
<script src="/Live2dHistoire/live2d/js/message.js"></script>
<!-- <![endif]-->
</body>
</html>

421
2020/06/17/backup.html Normal file
View File

@@ -0,0 +1,421 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- Begin Jekyll SEO tag v2.8.0 -->
<title>论备份的重要性 | Mayx的博客</title>
<meta name="generator" content="Jekyll v3.9.5" />
<meta property="og:title" content="论备份的重要性" />
<meta name="author" content="mayx" />
<meta property="og:locale" content="zh_CN" />
<meta name="description" content="只有事情发生到自己头上才想到要解决" />
<meta property="og:description" content="只有事情发生到自己头上才想到要解决" />
<meta property="og:site_name" content="Mayx的博客" />
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2020-06-17T00:00:00+08:00" />
<meta name="twitter:card" content="summary" />
<meta property="twitter:title" content="论备份的重要性" />
<meta name="google-site-verification" content="huTYdEesm8NaFymixMNqflyCp6Jfvd615j5Wq1i2PHc" />
<meta name="msvalidate.01" content="0ADFCE64B3557DC4DC5F2DC224C5FDDD" />
<meta name="yandex-verification" content="fc0e535abed800be" />
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"BlogPosting","author":{"@type":"Person","name":"mayx"},"dateModified":"2020-06-17T00:00:00+08:00","datePublished":"2020-06-17T00:00:00+08:00","description":"只有事情发生到自己头上才想到要解决","headline":"论备份的重要性","mainEntityOfPage":{"@type":"WebPage","@id":"/2020/06/17/backup.html"},"publisher":{"@type":"Organization","logo":{"@type":"ImageObject","url":"https://avatars0.githubusercontent.com/u/17966333"},"name":"mayx"},"url":"/2020/06/17/backup.html"}</script>
<!-- End Jekyll SEO tag -->
<link rel="canonical" href="https://mabbs.github.io/2020/06/17/backup.html" />
<link type="application/atom+xml" rel="alternate" href="/atom.xml" title="Mayx的博客" />
<link rel="alternate" type="application/rss+xml" title="Mayx的博客(RSS)" href="/rss.xml" />
<link rel="alternate" type="application/json" title="Mayx的博客(JSON Feed)" href="/feed.json" />
<link rel="stylesheet" href="/assets/css/style.css?v=1770554153" />
<!--[if !IE]> -->
<link rel="stylesheet" href="/Live2dHistoire/live2d/css/live2d.css" />
<!-- <![endif]-->
<link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="Mayx的博客" />
<link rel="webmention" href="https://webmention.io/mabbs.github.io/webmention" />
<link rel="pingback" href="https://webmention.io/mabbs.github.io/xmlrpc" />
<link rel="preconnect" href="https://summary.mayx.eu.org" crossorigin="anonymous" />
<link rel="prefetch" href="https://www.blogsclub.org/badge/mabbs.github.io" as="image" />
<link rel="blogroll" type="text/xml" href="/blogroll.opml" />
<link rel="me" href="https://github.com/Mabbs" />
<script src="/assets/js/jquery.min.js"></script>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-ajaxtransport-xdomainrequest/1.0.3/jquery.xdomainrequest.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<script>
var lastUpdated = new Date("Sun, 08 Feb 2026 20:35:53 +0800");
var BlogAPI = "https://summary.mayx.eu.org";
</script>
<script src="/assets/js/main.js"></script>
<!--[if !IE]> -->
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async="async" src="https://www.googletagmanager.com/gtag/js?id=UA-137710294-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-137710294-1');
</script>
<script src="/assets/js/instant.page.js" type="module"></script>
<!-- <![endif]-->
</head>
<body>
<!--[if !IE]> --><noscript><marquee style="top: -15px; position: relative;"><small>发现当前浏览器没有启用JavaScript这不影响你的浏览但可能会有一些功能无法使用……</small></marquee></noscript><!-- <![endif]-->
<!--[if IE]><marquee style="top: -15px; position: relative;"><small>发现当前浏览器为Internet Explorer这不影响你的浏览但可能会有一些功能无法使用……</small></marquee><![endif]-->
<div class="wrapper">
<header class="h-card">
<h1><a class="u-url u-uid p-name" rel="me" href="/">Mayx的博客</a></h1>
<img src="https://avatars0.githubusercontent.com/u/17966333" fetchpriority="high" class="u-photo" alt="Logo" style="width: 90%; max-width: 300px; max-height: 300px;" />
<p class="p-note">Mayx's Home Page</p>
<form action="/search.html">
<input type="text" name="keyword" id="search-input-all" placeholder="Search blog posts.." />&#160;<input type="submit" value="搜索" />
</form>
<br />
<p class="view"><a class="u-url" href="/Mabbs/">About me</a></p>
<ul class="downloads">
<li style="width: 270px; border-right: none;"><a href="/MayxBlog.tgz">Download <strong>TGZ File</strong></a></li>
</ul>
</header>
<section class="h-entry">
<small><time class="date dt-published" datetime="2020-06-17T00:00:00+08:00">17 June 2020</time> - 字数统计3822 - 阅读大约需要14分钟 - Hits: <span id="/2020/06/17/backup.html" class="visitors">Loading...</span></small>
<h1 class="p-name">论备份的重要性</h1>
<p class="view">by <a class="p-author h-card" href="//github.com/Mabbs">mayx</a></p>
<div id="outdate" style="display:none;">
<hr /><p>
这是一篇创建于 <span id="outime"></span> 天前的文章,其中的信息可能已经有所发展或是发生改变。
</p>
</div>
<script>
daysold = Math.floor((new Date().getTime() - new Date("Wed, 17 Jun 2020 00:00:00 +0800").getTime()) / (24 * 60 * 60 * 1000));
if (daysold > 90) {
document.getElementById("outdate").style.display = "block";
document.getElementById("outime").innerHTML = daysold;
}
</script>
<hr />
<b>AI摘要</b>
<p id="ai-output">这篇文章讲述了作者在云服务器Vultr上遭遇数据丢失的经历由于服务器突然挂掉且回滚到的快照时间较早导致十几天的数据可能丢失。作者在服务器故障后发现Vultr未能有效恢复数据恢复仅能依靠旧的快照这让他反思了备份的重要性和供应商责任。他计划设置自动快照脚本以防止未来类似问题并考虑将数据备份到本地以增加安全度。作者认为个人不能完全依赖云服务商备份是保障数据安全的关键。</p>
<hr />
<ul><li><a href="#起因">起因</a></li><li><a href="#难以想象的垃圾服务商vultr">难以想象的垃圾服务商Vultr</a></li><li><a href="#亡羊补牢">亡羊补牢</a><ul><li><a href="#自动快照的脚本">自动快照的脚本</a></li></ul></li><li><a href="#后记">后记</a></li></ul>
<hr />
<main class="post-content e-content" role="main"><p>只有事情发生到自己头上才想到要解决<!--more--></p>
<h1 id="起因">
<a href="#起因"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 起因
</h1>
<p>今天早上发生了一件很糟糕的事情,一打开聊天软件就发现有人在说我维护的花火学园挂掉了,错误信息是无法访问源站。我觉得挺奇怪,服务器又没啥负载,我也有一段时间没登进去了,怎么服务器就挂掉了? </p><p>
我试着用SSH连接同样无法连接我发现事情不太对劲然后就登到了Vultr里看了看。结果发现我的服务器在00:00之后就像一个死人一样CPU负载被拉成了一条直线就那样保持0%的位置。我以为是因为莫名其妙的原因服务器关机了,然而我重启以后仍然没有解决问题。 </p><p>
登录到终端一看,<code class="language-plaintext highlighter-rouge">No bootable device</code>就这样显示在屏幕上硬盘直接读不出来了这下可不得了了我赶紧去快照里看了一下发现最后一次快照的时间在5月30日也就是说如果没能恢复数据这十几天的所有信息都将消失</p>
<h1 id="难以想象的垃圾服务商vultr">
<a href="#难以想象的垃圾服务商vultr"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 难以想象的垃圾服务商Vultr
</h1>
<p>首先我要做的事情当然是想办法先恢复服务,虽然那个快照有点早,但是先顶上再说吧…… </p><p>
想一想我的防护应该做的也没啥问题而且一般成功入侵服务器的人也应该是删库然后留一条信息的那种直接干死硬盘的我还真没见过。于是我开始发Ticket给Vultr看看到底是怎么回事。 </p><p>
Vultr在我问完的4个小时后给出了最终的解决方案把我的服务器直接重置在上面安了新的操作系统然后给我赔了两个月的服务器费用……原文如下</p>
<blockquote>
<p>Hello,</p>
<p>In the past 24 hours, we sent notification of a node failure impacting your cloud server listed above.</p>
<p>Despite extensive efforts, our attempts to manually recover your cloud server were unsuccessful.</p>
<p>Our engineering team is currently deploying new instances with the same operating system and IP and you will receive login details in a separate message. You may also deploy a backup or snapshot on a new instance with a new IP if you prefer.</p>
<p>Our staff will be applying a two month account credit for the affected services shortly.</p>
<p>Regards, </p><p>
Bryan M. </p><p>
Systems Administrator</p>
</blockquote>
<p>这真是太糟糕了作为一家云服务器商就直接把客户的数据搞没了然后就赔2个月的费用要知道数据无价啊就这么不负责任的吗简直是不可思议啊 </p><p>
不过我也没什么好办法了也许他们不重装我还想着试试SystemRescueCD试试看能不能把整个磁盘复制出来但是他们既然已经直接重装那就彻底没救了……QAQ</p>
<h1 id="亡羊补牢">
<a href="#亡羊补牢"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 亡羊补牢
</h1>
<p>既然数据已经救不回来了,那我们也只能向前看,得想办法避免以后再出现这样的问题。因为我最近在期末阶段,比较忙,所以也不经常去打快照。虽然以前也出现过服务出问题的情况,像<a href="/2020/01/05/devops.html">MySQL挂了</a>、CDN挂了、还有一次好像是交换机出问题了但是无论如何数据从来没有丢失过。这一次数据都能丢了也真的是太糟糕了要不是有快照那就真成删库跑路了…… </p><p>
既然没时间打快照,我得想个办法搞一个自动打快照的东西。在网上搜了搜,还真有这样的脚本,于是我拿来改了改就装上去用了。</p>
<h2 id="自动快照的脚本">
<a href="#自动快照的脚本"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 自动快照的脚本
</h2>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">requests</span>
<span class="kn">from</span> <span class="nn">requests</span> <span class="kn">import</span> <span class="n">get</span>
<span class="kn">import</span> <span class="nn">re</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="k">class</span> <span class="nc">__RPC</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">api_key</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
<span class="bp">self</span><span class="p">.</span><span class="n">api_key</span> <span class="o">=</span> <span class="n">api_key</span>
<span class="bp">self</span><span class="p">.</span><span class="n">api_info</span> <span class="o">=</span> <span class="bp">None</span>
<span class="bp">self</span><span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
<span class="bp">self</span><span class="p">.</span><span class="n">errors</span> <span class="o">=</span> <span class="p">{</span>
<span class="mi">200</span><span class="p">:</span> <span class="s">"Function successfully executed."</span><span class="p">,</span>
<span class="mi">400</span><span class="p">:</span> <span class="s">"Invalid API location. Check the URL that you are using."</span><span class="p">,</span>
<span class="mi">403</span><span class="p">:</span> <span class="s">"Invalid or missing API key. Check that your API key is present and matches your assigned key."</span><span class="p">,</span>
<span class="mi">405</span><span class="p">:</span> <span class="s">"Invalid HTTP method. Check that the method (POST|GET) matches what the documentation indicates."</span><span class="p">,</span>
<span class="mi">412</span><span class="p">:</span> <span class="s">"Request failed. Check the response body for a more detailed description."</span><span class="p">,</span>
<span class="mi">500</span><span class="p">:</span> <span class="s">"Internal server error. Try again at a later time."</span><span class="p">,</span>
<span class="mi">503</span><span class="p">:</span> <span class="s">"Rate limit hit. API requests are limited to an average of 2/s. Try your request again later."</span>
<span class="p">}</span>
<span class="k">def</span> <span class="nf">api_info_initial</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="p">.</span><span class="n">api_info</span> <span class="o">=</span> <span class="p">{</span><span class="s">"snapshot/create"</span><span class="p">:</span><span class="s">"POST"</span><span class="p">,</span><span class="s">"snapshot/destroy"</span><span class="p">:</span><span class="s">"POST"</span><span class="p">,</span><span class="s">"snapshot/list"</span><span class="p">:</span><span class="s">"GET"</span><span class="p">,</span><span class="s">"server/list"</span><span class="p">:</span><span class="s">"GET"</span><span class="p">}</span>
<span class="k">def</span> <span class="nf">__getattr__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">eval</span><span class="p">(</span><span class="s">"__RPC"</span><span class="p">)(</span><span class="bp">self</span><span class="p">.</span><span class="n">api_key</span><span class="p">,</span> <span class="bp">self</span><span class="p">.</span><span class="n">name</span> <span class="o">+</span> <span class="s">"/"</span> <span class="o">+</span> <span class="n">name</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="p">.</span><span class="n">api_info</span><span class="p">:</span>
<span class="bp">self</span><span class="p">.</span><span class="n">api_info_initial</span><span class="p">()</span>
<span class="k">if</span> <span class="bp">self</span><span class="p">.</span><span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">.</span><span class="n">api_info</span><span class="p">:</span>
<span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="s">"The API is not exists."</span><span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span><span class="p">.</span><span class="n">api_info</span><span class="p">[</span><span class="bp">self</span><span class="p">.</span><span class="n">name</span><span class="p">]</span> <span class="o">==</span> <span class="s">"GET"</span><span class="p">:</span>
<span class="n">res</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"https://api.vultr.com/v1/"</span> <span class="o">+</span> <span class="bp">self</span><span class="p">.</span><span class="n">name</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="p">{</span><span class="s">"API-Key"</span><span class="p">:</span> <span class="bp">self</span><span class="p">.</span><span class="n">api_key</span><span class="p">},</span>
<span class="n">params</span><span class="o">=</span><span class="n">kwargs</span><span class="p">)</span>
<span class="k">elif</span> <span class="bp">self</span><span class="p">.</span><span class="n">api_info</span><span class="p">[</span><span class="bp">self</span><span class="p">.</span><span class="n">name</span><span class="p">]</span> <span class="o">==</span> <span class="s">"POST"</span><span class="p">:</span>
<span class="n">res</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">post</span><span class="p">(</span><span class="s">"https://api.vultr.com/v1/"</span> <span class="o">+</span> <span class="bp">self</span><span class="p">.</span><span class="n">name</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="p">{</span><span class="s">"API-Key"</span><span class="p">:</span> <span class="bp">self</span><span class="p">.</span><span class="n">api_key</span><span class="p">},</span> <span class="n">data</span><span class="o">=</span><span class="n">kwargs</span><span class="p">)</span>
<span class="k">if</span> <span class="n">res</span><span class="p">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">200</span><span class="p">:</span>
<span class="k">return</span> <span class="n">res</span><span class="p">.</span><span class="n">status_code</span><span class="p">,</span> <span class="n">res</span><span class="p">.</span><span class="n">text</span><span class="p">.</span><span class="n">strip</span><span class="p">()</span>
<span class="k">elif</span> <span class="n">res</span><span class="p">.</span><span class="n">status_code</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">.</span><span class="n">errors</span><span class="p">.</span><span class="n">keys</span><span class="p">():</span>
<span class="k">return</span> <span class="n">res</span><span class="p">.</span><span class="n">status_code</span><span class="p">,</span> <span class="bp">self</span><span class="p">.</span><span class="n">errors</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">res</span><span class="p">.</span><span class="n">status_code</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">res</span><span class="p">.</span><span class="n">raise_for_status</span><span class="p">()</span>
<span class="k">class</span> <span class="nc">Vultr</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">api_key</span><span class="p">):</span>
<span class="bp">self</span><span class="p">.</span><span class="n">api_key</span> <span class="o">=</span> <span class="n">api_key</span>
<span class="k">def</span> <span class="nf">__getattr__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">eval</span><span class="p">(</span><span class="s">"__RPC"</span><span class="p">)(</span><span class="bp">self</span><span class="p">.</span><span class="n">api_key</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span>
<span class="n">vultr</span> <span class="o">=</span> <span class="n">Vultr</span><span class="p">(</span><span class="s">"API Key"</span><span class="p">)</span>
<span class="n">data</span> <span class="o">=</span> <span class="p">{</span><span class="s">'SUBID'</span><span class="p">:</span> <span class="s">'实例ID'</span><span class="p">}</span>
<span class="n">status_code</span><span class="p">,</span> <span class="n">resp</span> <span class="o">=</span> <span class="n">vultr</span><span class="p">.</span><span class="n">snapshot</span><span class="p">.</span><span class="n">create</span><span class="p">(</span><span class="o">**</span><span class="n">data</span><span class="p">)</span>
<span class="n">requests</span><span class="p">.</span><span class="n">post</span><span class="p">(</span><span class="s">"https://sc.ftqq.com/SCKEY.send"</span><span class="p">,</span><span class="n">data</span> <span class="o">=</span><span class="p">{</span><span class="s">"text"</span><span class="p">:</span><span class="s">"快照已创建"</span><span class="p">,</span><span class="s">"desp"</span><span class="p">:</span> <span class="nb">str</span><span class="p">(</span><span class="n">status_code</span><span class="p">)</span><span class="o">+</span><span class="n">resp</span><span class="p">})</span>
<span class="c1"># 删除旧快照
</span><span class="n">status_code</span><span class="p">,</span> <span class="n">resp</span> <span class="o">=</span> <span class="n">vultr</span><span class="p">.</span><span class="n">snapshot</span><span class="p">.</span><span class="nb">list</span><span class="p">()</span> <span class="c1"># /v1/snapshot/list
</span><span class="k">if</span> <span class="n">status_code</span> <span class="o">!=</span> <span class="mi">200</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="s">'获取快照列表失败'</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">status_code</span><span class="p">)</span> <span class="o">+</span> <span class="n">resp</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="s">'成功获取到快照列表'</span><span class="p">)</span>
<span class="n">data_list</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">json</span><span class="p">.</span><span class="n">loads</span><span class="p">(</span><span class="n">resp</span><span class="p">).</span><span class="n">values</span><span class="p">())</span>
<span class="n">data_list</span><span class="p">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">[</span><span class="s">'date_created'</span><span class="p">])</span> <span class="c1"># 默认时间排序,由近到远
</span> <span class="n">data_list_del</span> <span class="o">=</span> <span class="n">data_list</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="mi">9</span><span class="p">:]</span> <span class="c1"># 取超过9个之后的快照
</span> <span class="k">for</span> <span class="n">data_del</span> <span class="ow">in</span> <span class="n">data_list_del</span><span class="p">:</span>
<span class="n">data</span> <span class="o">=</span> <span class="p">{</span><span class="s">'SNAPSHOTID'</span><span class="p">:</span> <span class="n">data_del</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'SNAPSHOTID'</span><span class="p">)}</span>
<span class="n">status_code</span><span class="p">,</span> <span class="n">resp</span> <span class="o">=</span> <span class="n">vultr</span><span class="p">.</span><span class="n">snapshot</span><span class="p">.</span><span class="n">destroy</span><span class="p">(</span><span class="o">**</span><span class="n">data</span><span class="p">)</span> <span class="c1"># /v1/snapshot/destroy
</span> <span class="k">if</span> <span class="n">status_code</span> <span class="o">!=</span> <span class="mi">200</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="s">'删除旧快照失败'</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="s">'成功删除一个旧快照'</span><span class="p">)</span>
</code></pre></div></div>
<p>把这个脚本放到Crontab里每天执行一次就行了。</p>
<h1 id="后记">
<a href="#后记"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 后记
</h1>
<p>相信服务器厂商是完全靠不住的事情自己还得想办法做好备份。我甚至在想阿三把Intel和微软都占领了会不会有一个阿三也跑到Vultr里然后对着我的硬盘大喊“把你变成咖喱”之类的23333。 </p><p>
现在不过是权宜之计,以后还是得想办法把整个论坛下载到本地,至少能搞个数据库的差异备份啥的也行啊……</p></main>
<small style="display: block">tags: <a rel="category tag" class="p-category" href="/search.html?keyword=%E5%A4%87%E4%BB%BD"><em>备份</em></a> <span style="float: right;"><a href="https://gitlab.com/mayx/mayx.gitlab.io/tree/master/_posts/2020-06-17-backup.md">查看原始文件</a></span></small>
<h4 style="border-bottom: 1px solid #e5e5e5;margin: 2em 0 5px;">推荐文章</h4>
<p id="suggest-container">Loading...</p>
<script>
var suggest = $("#suggest-container");
$.get(BlogAPI + "/suggest?id=/2020/06/17/backup.html&update=" + lastUpdated.valueOf(), function (data) {
if (data.length) {
getSearchJSON(function (search) {
suggest.empty();
var searchMap = {};
for (var i = 0; i < search.length; i++) {
searchMap[search[i].url] = search[i];
}
var tooltip = $('<div class="content-tooltip"></div>').appendTo('body').hide();
for (var j = 0; j < data.length; j++) {
var item = searchMap[data[j].id];
if (item) {
var link = $('<a href="' + item.url + '">' + item.title + '</a>');
var contentPreview = item.content.substring(0, 100);
if (item.content.length > 100) {
contentPreview += "……";
}
link.hover(
function(e) {
tooltip.text($(this).data('content'))
.css({
top: e.pageY + 10,
left: e.pageX + 10
})
.show();
},
function() {
tooltip.hide();
}
).mousemove(function(e) {
tooltip.css({
top: e.pageY + 10,
left: e.pageX + 10
});
}).data('content', contentPreview);
suggest.append(link);
suggest.append(' - ' + item.date + '<br />');
}
}
});
} else {
suggest.html("暂无推荐文章……");
}
});
</script>
<br />
<div class="pagination">
<span class="prev">
<a href="/2020/06/13/encrypt.html">
上一篇加密传输Demo V2
</a>
</span>
<br />
<span class="next">
<a href="/2020/07/29/card.html">
下一篇如何制作一个PCB名片
</a>
</span>
</div>
<!--[if !IE]> -->
<link rel="stylesheet" href="/assets/css/gitalk.css">
<script src="/assets/js/gitalk.min.js"></script>
<div id="gitalk-container"></div>
<script>
var gitalk = new Gitalk({
clientID: '36557aec4c3cb04f7ac6',
clientSecret: 'ac32993299751cb5a9ba81cf2b171cca65879cdb',
repo: 'mabbs.github.io',
owner: 'Mabbs',
admin: ['Mabbs'],
id: '/2020/06/17/backup', // Ensure uniqueness and length less than 50
distractionFreeMode: false, // Facebook-like distraction free mode
proxy: "https://cors-anywhere.mayx.eu.org/?https://github.com/login/oauth/access_token"
})
gitalk.render('gitalk-container')
</script>
<!-- <![endif]-->
</section>
<!--[if !IE]> -->
<div id="landlord" style="left:5px;bottom:0px;">
<div class="message" style="opacity:0"></div>
<canvas id="live2d" width="500" height="560" class="live2d"></canvas>
<div class="live_talk_input_body">
<form id="live_talk_input_form">
<div class="live_talk_input_name_body" >
<input type="checkbox" id="load_this" />
<input type="hidden" id="post_id" value="/2020/06/17/backup.html" />
<label for="load_this">
<span style="font-size: 11px; color: #fff;">&#160;想问这篇文章</span>
</label>
</div>
<div class="live_talk_input_text_body">
<input name="talk" type="text" class="live_talk_talk white_input" id="AIuserText" autocomplete="off" placeholder="要和我聊什么呀?" />
<button type="submit" class="live_talk_send_btn" id="talk_send">发送</button>
</div>
</form>
</div>
<input name="live_talk" id="live_talk" value="1" type="hidden" />
<div class="live_ico_box" style="display:none;">
<div class="live_ico_item type_info" id="showInfoBtn"></div>
<div class="live_ico_item type_talk" id="showTalkBtn"></div>
<div class="live_ico_item type_music" id="musicButton"></div>
<div class="live_ico_item type_youdu" id="youduButton"></div>
<div class="live_ico_item type_quit" id="hideButton"></div>
<input name="live_statu_val" id="live_statu_val" value="0" type="hidden" />
<audio src="" style="display:none;" id="live2d_bgm" data-bgm="0" preload="none"></audio>
<input id="duType" value="douqilai" type="hidden" />
</div>
</div>
<div id="open_live2d">召唤伊斯特瓦尔</div>
<!-- <![endif]-->
<footer>
<p>
<small>Made with ❤ by Mayx<br />Last updated at 2026-02-08 20:35:53<br /> 总字数617672 - 文章数179 - <a href="/atom.xml" >Atom</a> - <a href="/README.html" >About</a></small>
</p>
</footer>
</div>
<script src="/assets/js/scale.fix.js"></script>
<!--[if !IE]> -->
<script src="/assets/js/main_new.js"></script>
<script src="/Live2dHistoire/live2d/js/live2d.js"></script>
<script src="/Live2dHistoire/live2d/js/message.js"></script>
<!-- <![endif]-->
</body>
</html>