Luyu Huang's Tech Blog

自动生成 Lua 热更新代码

游戏服务器使用 Lua 的一个重要原因是 Lua 便于热更. 即使服务器正在运行, 只需让它执行一段代码, 即可重写其中的某些函数, 达到热更新的目的. 例如模块 app 有一个函数 foo local M = {} function M.foo(a, b) return a + b end return M 如果我们要将 foo 热更成将 a 和 b 相乘, 只需要让服务器加载运行如下代码即可: local M = require("app") function M.foo(a, b) return a * b end 不过很多时候, 函数并不是这么单纯. 函数常常会依赖许多上值 (upvalue), 举一个复杂点的例子: local databas...

Read more

由斜杠划分的区域

一月份 Leetcode 的每日一题几乎都是并查集. 不过个人认为与状态转移方程千变万化的动态规划相比, 并查集还是相对比较简单的. 这道题是我觉得最有趣的两道之一 (另一道是打砖块, 以后有时间的话也写一篇它的题解). 题目源自 Leetcode 959 题 在由 1 x 1 方格组成的 N x N 网格 grid 中,每个 1 x 1 方块由 /、\ 或空格构成。这些字符会将方块划分为一些共边的区域。 (请注意,反斜杠字符是转义的,因此 \ 用 "\\" 表示。) 返回区域的数目。 示例 1: 输入: [   " /",   "/ " ] 输出:2 解释:2x2 网格如下: 示例 2: 输入: [   " /...

Read more

Go 设置 socket 端口复用

我们知道, 一般来说, TCP/UDP 的端口只能绑定在一个套接字上. 当我们尝试监听一个已经被其他进程监听的端口时, bind 调用就会失败, errno 置为 98 EADDRINUSE. 也就是所谓的端口占用. int fd1 = socket(AF_INET, SOCK_DGRAM, 0); int fd2 = socket(AF_INET, SOCK_DGRAM, 0); struct sockaddr_in addr = {0}; addr.sin_family = AF_INET; addr.sin_port = htons(1234); addr.sin_addr.s_addr = inet_addr("127.0.0.1"); bind(fd1, (struct...

Read more

2020 Annual Summary

At the beginning of 2020, no one anticipated that we would face an unprecedented pandemic that would last a year or more. 2020 is unusual, to me, pandemic, new job, working, challenges, learning, vocabularies, and algorithms are key words of 2020. Time flies and everything will pass, we all hope that tomorrow will be better. For the summary of t...

Read more

详解 KCP 协议的原理和实现

1. 引言 KCP 是一个快速可靠的 ARQ (Automatic Repeat-reQuest, 自动重传请求) 协议, 采用了不同于 TCP 的自动重传策略, 有着比 TCP 更低的网络延迟. 实际通常使用 KCP over UDP 代替 TCP, 应用在网络游戏和音视频传输中. KCP 的实现短小精悍, 非常适合学习. KCP 的 ARQ 机制与 TCP 类似, 只是部分策略不同, 学习 KCP 也有助于我们理解 TCP. 本文讨论 KCP 的原理和实现, 包括它的 ARQ 机制, 拥塞控制等. 笔者并不想直接贴出大段代码然后逐行分析, 因此本文各节会先用图文介绍 KCP 的各个机制, 然后再展示代码并分析它的实现. KCP 源码的可读性还是比较好的, 建议大家阅读本文的同时...

Read more

Subsocks: 用 Go 实现一个 Socks5 安全代理

笔者最近读完了 The Go Programming Language, 想写点东西练练手. Go 比较适合写服务器软件, 之前又学习了下 Socks5 协议, 于是决定写一个 Socks5 代理服务器. 目前基本功能已经完成, 部分思路参考了 ginuerzh/gost. 我给它起名为 Subsocks, sub- 意为在 … 之下 (类似于 "subway"). 项目 Repository 在这里: luyuhuang/subsocks. 这里做一个介绍并简单总结下它的实现. 使用 一个 Subsocks 进程可以是客户端或服务端, 这取决于配置. 客户端会接收来自应用 (如浏览器) 的 Socks5 请求, 然后将其封装在指定的安全协议 (如 HTTPS) 中, 然后发送给服...

Read more

Printing parameters in Lua traceback

When an error occurs, Lua will print a traceback of the call stack, it helps us to find bugs. In many cases, however, a call stack traceback is not enough for us to find out the problem. We need more information, such as the environment, parameters of each function call, even all local variables of the stack. I decide to modify Lua to improve t...

Read more

Lua 夏令时时区问题

我之前的一篇文章介绍了怎样在服务器和客户端之间同步时间和时区. 同步时间相对简单些, 本质就是一个时间差; 而时区相对复杂些. 那篇文章介绍的方法有一个问题: 在客户端的时区启用了夏令时的时候, 客户端得到的本地时间会比实际快一个小时. 原因是求客户端时区的方法不对. 例如, 太平洋时区本为 UTC-0800, 而当客户端处于太平洋时区的 2020 年 10 月 29 日, 此时太平洋时区启用夏令时, 时区应为 UTC-0700. 如果使用这样的方法 local now = os_time() local CLIENT_TIMEZONE = math.floor(os.difftime(now, os_time(os_date("!*t", now)))) 求得的时区 CLIEN...

Read more