Luyu Huang's Tech Blog

Switch 语句的语义

switch 语句一般用于多重分支选择. 不过 switch 的语义与 if ... else if 完全不同, 它更像是 goto 语句. switch 只接一个语句块, 语句块中可以包含一些 case 跳转标签, switch 先对表达式求值, 然后跳转至对应的标签. break 可以跳出 switch 语句. switch (state) { case 1: foo(); break; case 2: bar(); break; } 因为 switch 语句是简单粗暴的跳转, 所以它并没有什么结构性可言. 所以我们可以写出一些奇奇怪怪的 switch 语句: int n, i = 0; swi...

Read more

DWords2: 全新版本的弹幕背单词

我觉得通过弹幕背单词是个好主意, 不过一年多前我用 Python 写的那个软件有点太简陋了, 局限性比较强, 而且放到现在还有各种兼容性问题. 因此这次我重写了 DWords, 全新版本使用 Electron 开发, 界面 (相对一代的烂界面) 要好看得多, 且新增了一些功能. 新版本使用 WebDAV 同步, 用坚果云就可以很好地同步了, 比一代的邮件同步强很多. 项目主页 | 下载地址 主要功能 弹幕除了显示释义外, 还有音标, 发音按钮, 以及外部词典链接. 外部词典可以自定义. 弹幕大小, 移动速度, 颜色和透明度都可设置, UI 相对一代精细很多. 支持学习计划, 可以从词库创建学习计划. 支持常用的词库如四六级, 考研, 雅思等. 当然也支持自定义计划, 学...

Read more

基于 TCP 的应用层协议设计

一直以来, 包括我在内的很多人都认为, 基于 TCP 的应用层协议很简单, 只需要加个包头就行了. 因为 TCP 是可靠的协议, 能保证数据有序无误地送达对端; 只是它面向流, 不保留消息边界, 因此我们只需要定义协议包头, 能区分各个数据报即可. 然而这个看法是错误的: 传输层协议所做的工作是有限的, 应用层协议的工作远不止封装一个包头. 我们来看个例子. TCP 连接并不是那么可靠 我们用 C 写一个简单的客户端. 它用 TCP 连接上服务器, 然后 sleep 一段时间, 然后调用 send(2) 发送一段数据. int main() { int fd = socket(PF_INET, SOCK_STREAM, 0); struct sockaddr_i...

Read more

在自己的博客上启用 Tab 键搜索

Chrome 浏览器有一个功能, 在地址栏输入域名后按下 Tab 键, 就可进入搜索状态. 这让我们很方便地搜索一个网站的内容. 这个功能称作 Tab to Search. 当然不是每个网站都支持, 毕竟不同网站的搜索接口都不一样. 不过, 这个功能并不是 Chrome 专门为一些知名网站做的适配, 而是通过一个开放性标准 OpenSearch description format 实现的. 只要你的网站符合这个规范就能支持 Tab to Search. 实现起来非常简单. 首先在网站主页的 <head> 标签里加一个链接, 指向一个 OpenSearch description. <head> <link rel="search" ty...

Read more

Beware of Hash Collisions in Lua Tables

We all know that a Lua table is a hash table, which uses a hash function to map a key into one of the table's slots. However, the result of the hash function is not unique. There exist some keys that have the same hash value, i.e., it may map some different keys into the same slot. We call it Hash Collision. To observe hash collisions in a Lua ...

Read more

用树莓派搭建一个能在外网访问的 NAS

我最近买了一个树莓派, 想用它搭建一个 NAS. 对此我有几点要求: 能在外网访问 启用 HTTPS 内外网使用相同的访问方式, 无缝切换 我准备使用 NextCloud, 因为它支持 WebDAV, 这样可以作为 Joplin 的同步服务器. 我之前在外网 VPS 上搭建过一个 NextCloud, 现在我准备把它迁移到我的树莓派上, 感觉数据还是放在自己身边更可靠些. 我购买的是树莓派 4B, 内存 4GB, 32GB 空白存储卡; 再加上我 2 TB 的西部数据移动硬盘作为数据盘. 这篇文章记录我是怎么做的. 安装操作系统 操作系统的安装比较简单. 我安装的是 Ubuntu Server 20.04. Ubuntu 对树莓派的支持还是非常好的, 官网...

Read more

Jump Consistent Hash 算法

这篇文章我们讨论 Jump Consistent Hash 算法, 一个极简且高效的一致性哈希算法. 哈希与一致性哈希 哈希函数, 或者说散列函数, 能将一个较大定义域中的元素映射到一个较小的有限值域中. 值域中的元素有时也称为桶 (bucket), 值域的大小亦称为桶的数量. MD5 就是一种常用的哈希函数, 它能将任意大小的数据 (较大的定义域) 映射成一个 16 字节的哈希值 (较小的有限值域). 最简单的哈希函数就是取模, 它能将全体整数 (较大的定义域) 映射到一个整数区间 (较小的有限值域) 中. 假设我们的服务器有 3 个工作进程, 同时为用户提供服务. 这些工作进程的功能是相同的, 并且会保存用户的状态数据. 那么如何决定一个用户由哪个工作进程提供服务呢? 最简...

Read more

ZooKeeper 入门教程

ZooKeeper 是一个分布式服务中间件, 乍一看有点像一个 NoSQL 数据库系统. 不过它的主要功能不是存储数据, 而是提供一种共享数据和服务间通信的方式, 使用它我们能够更方便地开发分布式软件. 这篇文章介绍 ZooKeeper 的主要特性, 使用方式和应用场景. 主要特性 我们先来看一下 ZooKeeper 的主要特性, 以及它跟 NoSQL 数据库系统不同的地方. 数据存储 不同于 Redis 的 key-value 结构, ZooKeeper 将所有的数据管理在一个树状结构中. 这个结构很像文件系统, 一个路径标识一个节点, 由若干个用斜杠隔开的名字组成. 根结点路径为 /, 因此路径总是由斜杠开头. 与文件系统不同的是, ZooKeeper 中叶子结点和内...

Read more