From BitTorrent to Firewall

服务器能做什么?在 Awesome-Selfhosted 里可以找到上百种答案。如果带宽不算太小的话,那么 BT 下载是个不错的尝试。借着 No Time to Die 的上映我开始重温 007 系列,从皇家赌场到幽灵党,在服务器上的下载体验是很好的。 BitTorrent 在此之前,我基本上把 BT、种子、磁力、迅雷下载当成同一种东西。下载电影?先找种子或者磁力链接,打开迅雷下载,然后视速度决定要不要开个会员。 实际上这完全曲解了 BT 下载。 首先 BitTorrent 是一种网络协议。还记得计算机网络一开始就提到过除了 C/S 架构之外,还有 P2P(Peer-to-peer),也就是网络中的各个节点都扮演了同等的角色,既是客户端也是服务器。BT 基于 P2P 实现了去中心化的文件分享,让网络数据的传输不再仅限于服务器的能力,而是共享带宽,每个人下载的同时也在上传,所以越多人参与速度就越快。 类似于 HTTP 和 FTP,BT 也是基于 TCP/IP 的一种应用层协议。基本上它是这么运作的: 我有一部电影,想把资源分享到网络,要先提供一个种子文件 种子文件实际上就是个文本文件,里面主要记录两部分信息 Trackers: 就是 Tracker 服务器的地址,这个服务器不是用来下载资源的,而是用于获取其他 Peers 的联系方式 Files: 一个视频文件会被(逻辑)划分为很多个虚拟分块,每块的索引和验证码都包含在这里 接下来我把种子文件发布出去,等待别人下载 这时候有人获取到种子了,于是开启了 BT 客户端下载 客户端先解析种子文件中的信息,找到 Tracker,然后询问有哪些 Peers 因为是第一个下载者,所以 Tracker 告知 Peer 目前只有我,也就是发布者...

12-20 · 2 min

Even Dead, You're The Hero

愿逝者安息。 同龄人,也算是同行,现在几乎不玩游戏了,但从小也在国产武侠 RPG 里泼洒了许多热情。虽然不认识,之前也未曾耳闻,心里却五味杂陈。一切的一切,我都理解的。 我有一个梦想,将来的某一天,大家都能玩到蕴含着中国上下五千年本土文化的优质游戏大作。 我有一个梦想,有一天,西游记能出ACT,让老外去体会中国文化西游记中”斗战胜佛”的打击快感,那一定比西方的动作巅峰之作《战神》、《鬼泣》更加深邃。 … 我有一个梦想,将来的某一天,国产游戏能像中国的其他产业一样,以一个领跑者的姿态,面对全世界,面对全宇宙,器宇轩昂,扬眉吐气。 … 我等着我们的好消息。 Even Dead, You’re The Hero.

12-14 · 1 min

Python heapq 源码阅读

Heap 作为一种重要的数据结构,有许多应用场景,比如优先级队列,每次出队的都是最大值或者最小值的元素。很多语言都集成了相关实现,比如 Java 的 PriorityQueue,而 Python 提供了 heapq 模块。 因为 Heap 通常用数组而不是链表存储,所以 Python 里面的 Heap 实质上就是一个列表,而 heapq 提供的几个函数也是以列表对象作为参数的: from heapq import heappush, heappop, heappify, heapreplace, heappushpop heap = [] heappush(heap, 1) item = heap[0] # 第一个元素代表堆顶元素 heappop(heap) heapify([3, 2, 1, 5, 6, 4]) # 把普通列表转化为堆结构 [1, 2, 3, 4, 5, 6] heapreplace([3, 4, 5], 1) # 直接将堆顶元素 3 替换为 1,最后堆结构为 [1, 4, 5] heappushpop([3, 4, 5], 1) # 先将 1 插入堆中,再 pop 出堆顶元素,最后堆结构为 [3, 4, 5] 为什么 heapq 提供的是最小堆而不是更常见的最大堆呢?这就得从源码中找答案了。...

11-29 · 4 min

Python OrderedDict 实现 LRU 缓存

LRUCache 是一种经典的缓存机制,它的基本思路是按照最近使用的时间对元素排序,在清理时优先把搁置最久的删除掉。 如果不想给每个缓存元素都记录一个时间戳的话,可以应用哈希链表来简单地实现 LRU 算法。也就是对一个哈希表中的所有元素增加指针,从而串起一个双链表,这样既可以快速 get value,又可以通过把最近使用过的元素放到头部来维护顺序,删除的时候从末尾开始就好了。 手写双链表并不困难,但是借助 OrderedDict 的话,可以写出非常简短的代码: from collections import OrderedDict class LRUCache: def __init__(self, capacity): self.capacity = capacity self.hashtable = OrderedDict() def get(self, key: int) -> int: if key in self.hashtable: self.hashtable.move_to_end(key, last=False) return self.hashtable[key] return -1 def put(self, key: int, value: int) -> None: self.hashtable[key] = value self.hashtable.move_to_end(key, last=False) if len(self....

11-28 · 3 min

Numeric Strings in Python

Python 的字符串自带了三种判断字符是否为数字的方法,但实际用处却相差很多。 TL;DR 三种方法 isdecimal < isdigit < isnumeric,即包含的范围越来越大 除了 ASCII 字符以外,对于 Unicode 的字符也都覆盖在内 三种方法对于小数点和负号都会返回 False 三种方法对于空字符串都会返回 False 比较简便判断数字字符串的方法:直接使用 float 方法并检测 ValueError Decimal & Digit & Numeric 对于 isdecimal, isdigit 和 isnumeric 三种方法,目的并不是判断字符串是不是一个有效数字,而是针对每一个字符的校验: isdecimal: 判断字符串中的字符是否都为 Decimal,也就是在 Unicode 中类别为 Nd 的字符 isdigit: 除了 isdecimal 包含的范围之外,还会判断字符是否都为 Digit,即 Unicode 的 Numeric_Type 为 Digit 或 Decimal isnumeric: 除了 isdigit 包含的范围之外,还会判断字符是否都为 Numeric,即 Numeric_Type 为 Numeric 所以这三种方法覆盖的字符范围,每一个都是前一个的超集。对于超出 ASCII 字符之外的效果,比如: “0123456789” 这种 Full-width 字符串 isdecimal 会判定为 True,后两个方法也一样 “⓪①②③④⑤⑥⑦⑧⑨” 这种 Circled-digit 字符串 isdecimal 判定 False,但 isdigit 和 isnumeric 为 True “一二三四五六七八九十壹貳參肆伍陸柒捌玖拾” 这种中文数字字符串只有 isnumeric 才会判定为 True 总之这几种方法有更广泛的用途,根本不是为了简单的 ASCII 数字字符串的判断。即使用来做判断的话,局限性也非常大,因为如果包含小数点和负号,三个方法都会返回 False....

11-21 · 1 min