读《大型网站技术架构》

这本书偏知识型,比较接地气,总结梳理的不错,内容深度一般化,花一个周末就可以读完~

一图胜万言:(PS. 书中案例部分比较浅, 没有包含在下图中)


Reed-Solomon 编码算法

Reed-Solomon (RS) 是一种纠错码算法, 纠错码是说对原始数据通过计算得到检验数据, 根据这些冗余的校验数据, 可以保证原始数据的可恢复性.

极大距离可分法(Maximun Distance Seperable codes, MDS) 是一种很常见的纠错码: 将原始数据分成等长的 n 份, 并根据这 n 份数据生成 m 个冗余的校验数据, 这样, 这 m+n 块数据中任意 m 块数据损失, 也可以通过剩下的 n 块数据计算得到. RS 是经典的 MDS 算法.

理论基础一: 有限域算法


业务建模学习

要点回顾

回顾一下前文中的提到的部分软件方法流程:

  • 愿景: 明确目标组织和老大.
  • 业务建模之业务用例图: 以组织提供的价值为依据(对组织的期望), 输出组织的用例.
  • 业务建模之业务序列图: 以现状业务序列图为基础, 将待开发的系统作为新的业务实体插入, 寻找改进点, 减少人肉.
  • 需求之系统用例: 从业务序列图直接映射.

《软件方法》学习

一、建模与 UML

《软件方法》聚焦两方面的技能: 需求 & 设计.

作者提出一个适用于软件行业的观点:


支付业务背景知识梳理之二: 支付与清算

支付、清算和结算

支付: 社会经济活动所引起的货币债权转移的过程, 通俗点来说, 一般是指发生发生交易 A 付钱给 B 的交互行为, 包括交易 & 清算 & 结算.

随手 yy 一个案例: 王大妈在菜市场花 5 元买了两把小白菜, 买小白菜是交易, 两把小白菜需要 5 元是清算, 王大妈付给商贩 5 元是结算.


支付业务背景知识梳理之一: 复试记账

复式记账法

百科上的解释如下:

每笔交易都至少记录在两个不同的账户当中。每笔交易的结果至少被记录在一个借方和一个贷方的账户,且该笔交易的借贷双方总额相等。


商户微信支付能力梳理

最近在学习微信支付的业务, 简单梳理下当前商户微信支付的能力及相关接口. (PS: 注意是商户, B2C 或者 B2B, 个人发红包转账之类的 C 端不涵盖在内).

大部分资料都来自《官方开发文档》官方的视频教程.

支付模式


关于 docker 的一些总结和观点

docker 背后的技术支撑

1. namespaces 资源隔离

The purpose of each namespace is to wrap a particular global system resource in an abstraction that makes it appear to the processes within the namespace that they have their own isolated instance of the global resource, 即每个 namespace 实例拥有一份隔离的全局资源, 这些全局资源目前包括了:


网络数据帧与 MTU

以太帧(Ethernet Frame)

以太帧的发展历史得从以太网说起:

  • 1973 年, Bob Metcalfe 在 Xerox 和同事一起发明了以太网, 具体过程可以参考 以太网的发展历史.
  • 1979 年, Metcalfe 成立 3Com 公司, 并对 DEC, Intel 和 Xerox 进行游说, 希望与他们一起将以太网标准化, 规范化.
  • 1980 年, 3Com 和 DEC, Intel, Xerox 一起标准化以太帧的封装格式, 即 Ethernet V1.
  • 1982 年, 3Com 和 DEC, Intel, Xerox 一起, 公布新的以太帧标准, 电气和物理接口有更新, 协议格式并无变化, 即 Ethernet V2, 又叫 ARPA.
  • 1984 年, RFC 894 定稿, 指定了以太帧封装 IP 报文的协议标准.

分布式系统的接口幂等性设计

概念

幂等性, Idempotence, 这个词来源自数学领域, 百科上一元运算的幂等性解释如下:

设 f 为一由 {x} 映射至 {x} 的一元运算, 则 f 为幂等的, 当对于所有在 {x} 内的 x: f(f(x)) = f(x) 特别的是,恒等函数一定是幂等的,且任一常数函数也都是幂等的。


【笔记】读卡马克《Parallel Implementations》

在浏览知乎的一个讨论: 《入职后发现项目组代码异常混乱,是去是留?》, 顾露同学的回答中提到了这篇文章,所以就追根溯源去读了一下. 因为原博客《AltDevBlogADay》已经关闭了, 可以从这里看到全文。

摘抄文中比较有意思的几段:

>

I used to Code Fearlessly all the time, tearing up everything whenever I had a thought about a better way of doing something. There was even a bit of pride there — “I’m not afraid to suffer consequences in the quest to Do The Right Thing!” Of course, to be honest, the consequences usually fell on a more junior programmer who had to deal with an irate developer that had something unexpectedly stop working when I tore up the code to make it “better”.


Lock-Free 学习总结

Lock-Free

Lock-Free:

如果一个方法是 Lock-Free 的, 它保证线程无限次调用这个方法都能够在有限步内完成.


【笔记】优秀的手游团队

阅读来源: “优秀手游团队三要素:决策、实现、品质”}

文中对游戏研发团队提出了三点要素:

  • 产品方向的决策;
  • 能把控节奏的高执行力;
  • 内心对游戏的品质的追求;

虽然文章的视角相对狭隘, 但是总结出来的几点还是比较中肯的.


启发式寻路算法

启发函数 (Heuristic Function)

盲目搜索会浪费很多时间和空间, 所以我们在路径搜索时, 会首先选择最有希望的节点, 这种搜索称之为 "启发式搜索 (Heuristic Search)"

如何来界定"最有希望"? 我们需要通过 启发函数 (Heuristic Function) 计算得到.


弱网络下的可靠UDP研究

前言

这是一个公司内组织的业余研究小组活动,我找了关于手游弱网相关的课题,并在为期12周的过程中,和专家导师一起细化方向,阅读相关材料,做了一些测试实验.

虽然因为时间有限,几乎没有太多深度,但是对于个人开拓视野颇有帮助,特别是跟着专家学习了做课题研究的方法方式,在这里记录一下历程。


跨平台命令行抓包工具 gaze 介绍

gaze 是什么

gaze 是一个命令行下的轻量级网络包监听工具, 有颜色显示, 跨平台(linux \& windows), 支持 TCP 协议, 支持自定义插件扩展.

能做网络抓包的工具很多, 例如 tcpdump 和 wireshark, 为什么还要重写一个? gaze 工具的初衷是为了提高业务联调的效率. 之前在项目中使用过 wireshark 和它的 Lua 插件, 但是在 Linux 下使用不方便. 而 tcpdump 客户端在 Windows 下也不太方便使用, 所以会有这个需求.


【译】《帝国时代》中的网络编程

写在前面

《原E文》的题目比较长, 全译过来是: "28.8k网络环境下的1500个弓手: 《帝国时代》中的网络编程及未来".

因为原文的写作时间比较早, 所以文中提到的很多硬件和网络环境, 在现在看都已经过时了, 但是并不妨碍我们学习它的设计理念和网络模型.


SSL/TLS协议

基本概念

SSL (secure sockets layer) 和 TLS (transport layer security) 都是传输层的安全协议(在协议栈中处于TCP协议和应用层协议中间), 对网络连接和数据传输进行加密.

  • 1994年, NetScape 公司设计了 SSL 1.0 版, 但是未发布.
  • 1995年, NetScape 公司发布 SSL 2.0 版, 很快发现有严重漏洞.
  • 1996年, SSL 3.0 版问世, 得到大规模应用.
  • 1999年, 互联网标准化组织 ISOC 接替 NetScape 公司, 发布了 SSL 的升级版 TLS 1.0.
  • 2006年和2008年, TLS 进行了两次升级, 分别为 TLS 1.1 和 TLS 1.2

网络缓冲区随笔

在服务器处理网络连接(本文中仅讨论TCP连接的情况)时,常常会构建一块 buffer,来存储收到的网络数据,直到确认收到的数据已经处理完,才会从 buffer 中清除。

从功能来看,就是开一块内存,满足不断的读写数据需求。这里不考虑恶意连接或者恶意数据包.

为了提高 buffer 效率,需要考虑的几点:

  • 多连接的情况,例如网关,会有频繁的建立、断开 TCP 连接,要考虑 buffer 内存碎片的问题.
  • 减少内存拷贝的开销.

游戏中的网络同步

网络对时

大部分的强交互网游会做对时, 使 client 和 server 保持时间基本一致.


【笔记】软件工程设计原则

每次看到这些 principles, 总能多一些体会.

单一职责原则(Simple responsibility pinciple, SRP).

这在 Unix 文化中展现的淋漓尽致. 提炼职责是关键, 提炼重复的代码, 提炼相似的业务, 乃至提炼对领域模型的抽象.

依赖倒置原则(Dependence Inversion Principle, DIP).


利用共享内存实现进程间通信

共享内存通信的好处

进程间通信有很多的选择,socket,共享内存,管道等等。

在设计网络游戏服务器的时候,一个比较常见的做法是在同一台机器上将网络接入和游戏逻辑分成不同进程,然后通过共享内存去通信.


Lua 游戏开发学习

使用 Lua 带来的便利性

个人经历过的大部分游戏服务器项目, 用到 Lua 的地方都不多, 借着这次重构项目的机会, 可以好好学习一下. Lua 在游戏开发中有很多优点:

  • 业务逻辑开发效率的提升, 这点在业务复杂的 mmo 项目中尤为明显.
  • 摆脱繁重的数据配置, 当然策划是基本指望不上的.
  • 天然的热加载机制, 无论是配置还是业务逻辑, 都可以很方便的做不停服更新.
  • Lua 虚拟机提供了一个安全的沙箱, 增强了服务器的稳定性, 至少不用太过于担心线上的 coredump.
  • Lua 语言提供的 coroutine 机制, 可以很容易的维护多状态的异步逻辑, 比起多线程 C/C++ 来的更轻量.

【笔记】项目管理与团队

前端时间去听了一门课程: 《项目管理基础》, 大部分东西比较务虚, 但是还是有一些收获的, 做点笔记.

项目管理的过程:

  1. 启动, 需求分析, 组建团队;
  2. 计划, 制定目标和关键路径, 成本估算和风险管理;
  3. 执行 & 控制, 包括了进度控制, 变更管理, 计划即是为了变化, 迭代和周期随之变更;
  4. 收尾, 最后的项目交付和总结;

与项目管理密切相关的是 团队的成长过程:


【笔记】大R的心理

阅读原文: 霸道总裁玩游戏:你不知道的“大R心理学”}

文中阐述了三点观点:

  1. 想买什么就买什么: 有想要的东西不去计较价格立即买到手.

  2. 什么最新最好就买什么: 但是要让大R明白什么最好也不是件容易的事情, 付费内容免费体验是个不错的手段.

  3. 寻求存在感的炫耀性消费: 例如刷全屏喇叭.

个人观点: 让大R玩家花最多的钱买最好的服务, 在屌丝玩家面前炫耀, 最终都是满足了他们的"情感"乃至"尊重"需求. 我们应该围绕满足、尊重、炫耀这一系列心理历程来做设计.


【笔记】产品竞争力和技术追求

今天读了一篇博文, 《从Linux内核升级的必要性说开去》, 有一些不错的观点, 摘录如下:

  1. “关键不是你保留了多少别人不知道的技术细节, 关键在于你能多快推出一个可以使用的五脏俱全的最简版本, 并且能以多快的频率持续更新, 持续优化, 而这一切很大的分量上并不是你自己闭门顿悟的, 而是来自使用者的反馈. 快, 才是根本.”

  2. “别人不曾想到的那些易用的功能, 你自己提炼出来的可能的新的需求, 这些才是竞争力, 而不是其实现.”

  3. “从Linux内核说开去, 任何的开源代码其价值不仅仅是最终形成的软件本身的自由使用分发, 它内部实现本身就是一座宝库, 你可以从中得到很多的东西不过, 仅仅拿来是无耻的, 必须保持一颗时刻分享的心.”

作为一个网络游戏行业的从业者, 其实是很有一些共鸣的, 个人观点:

  1. 网游行业算的上互联网的一个分支, 整个互联网最强调的核心竞争力, 是用户体验至上, 这需要有快速迭代的能力. 还有一句话, 叫做“江湖武功, 唯快不破”. 这一点在手游领域里面体现的淋漓精致. 玩家才不会管你的客户端是unity还是cocos2d, 也不care你的服务器是C++还是php, 只要没有bug服务器不宕就是好样的.

  2. 做网游, 技术能力是基石, 客户端不无缘无故的崩溃, 服务器不宕机不随随便便维护, 这是游戏的基础生命线. 但是, 想要获得成功, 真正的核心竞争力还在于游戏的品质, 在于它的核心玩法是否足够吸引人. 为什么都说天美的手游做的好, 甚至于都形成了一个词: "天美品质", 这才是游戏的核心竞争力.

  3. 当然, 这不是说技术不重要, 如果前面所说的, 技术是基础, 是基石, 没有技术肯定是要完蛋的. 如何平衡技术的追求和对产品的把控, 这取决于思考问题的角度和身处的位置. 软工设计, 很大程度上也是在做妥协和平衡, 不是么?

  4. 反馈社会这件事情, 等到游戏开张赚到钱了再做不迟, 要是没有成功的产品和实践验证, 你去跟大家分享, 别人还以为你是大忽悠, 让大家给你当小白鼠呢.


【笔记】互联网思维

阅读来源: 《互联网思维下的产品观》

写的比较棒的一篇文章. 记录一点自己的思考. 假如我要去做一个传统行业, 按照互联网思维的套路, 需要怎么来处理:

  1. 用户: 用户至上的原则是放在第一位的, "封测"背后的逻辑: 倾听用户的声音, 重视用户的意见, 没事多泡泡贴吧和论坛, 跟用户混熟, 不管他是屌丝还是土豪, 每个人的内心都有强烈的情感和尊重的需求, 满足他们, 成败往往在细节.

  2. 速度: 实际上是"用户至上"的延伸, 在理解了用户的心声之后, 迅速的迭代优化, 满足用户的需求. 高速的迭代同时也是拉留存的必须手段, 人们总是喜欢新鲜, 前提是迭代后你的产品更好.

  3. 展示: 如何让用户知道你的产品, 互联网上有很多渠道: 网站, 论坛, 百度贴吧, 维基百科, 微信服务号, 微博, 移动APP, 等等, 如果需要做的好, 肯定是要花时间和精力的.

  4. 运营: 有了展示的平台, 还需要做运营活动, 来拉升用户和付费, 例如节日活动, 例如名人的噱头吸引眼球. 最好运营活动的关键之一, 在于数据分析.

  5. item 免费: 免费的最终目的是为了收费, 大量的免费用户是基数, 转化后的付费用户才是目的.

这两天正好又读到微信上一篇热文, 讲的更详细和全面.


【译】进程的内存剖析

2014 年 6 月 15 日

原e文博客地址在这里: 《Anatomy of a Program in Memory》, 偶然间看到的, 写的很清晰.

内存管理(MM)是OS的核心, 也是编程和系统管理的关键. 本篇文章主要分析了内存中的进程布局, sample则大部分来自32位X86架构下的Linux和Windows.

在多任务的操作系统中, 每个进程都运行在虚拟内存地址空间的沙盒中. 32位操作系统下, 这个空间是4GB. 虚拟内存地址地址, 根据页表(page table)映射成物理地址, 页表由kernel维护, 进程向kernel查询. 每个进程都有自己的页表集, 但是有一个小trick: 虚拟内存地址空间作用于所有的进程, 包括kernel自身, 所以需要预留一部分地址空间给kernel.


Linux 之 VM

2014 年 6 月 15 日

虚拟存储

虚拟存储(virtual memory, VM)的基本思想是: 维护一个虚拟的逻辑内存机制(通常比物理内存大得多), 进程都基于这个虚拟内存, 在进程运行时动态的将虚拟内存地址映射到实际的物理内存.


NaN tricks in Lua

最近在读云风的《reading lua》,看到了一个浮点数 NAN trick 的应用,觉得比较有意思,结合代码和相关资料总结一下。

什么是 NaN

在浮点数中,NaN 用来表示特殊值,在一些未定义的操作中,会生成 NaN,具体的例子可以参考 wiki.


Linux 系统监控

2014 年 5 月 13 日

CPU 监控

(1) /proc/cpuinfo 查看 CPU 的基本信息.


【笔记】ejoy2d —— spritepack

2014 年 3 月 12 日

在学习sprite之前, 先了解一下sprite_pack, lib/sprite_pack.h和lib/sprite_pack.c提供了底层的数据操作. ejoy2d/spritpack.lua封装了上层接口, 提供数据之间的打解包转换.

"这只是方便开发,在产品发行时不应该这样做". 从版本的安全性来说, 还需要做一些加密工作, 防止资源被破解.


单点服务与热备机制

2014 年 3 月 8 日}

逻辑层的单点服务

在游戏业务中, 一般都会尽量避免单点服务的存在, 但是难免会有些特例, 特别是全区全服的游戏中, 由于一些业务的特性, 很难做成分布式. 例如排行榜服务, 提供top的排名查询和更新;例如维护目录等meta信息的单master节点;例如提供创建名字和改名的name service等. 这些业务可以提炼出一些共性:


【笔记】ejoy2d —— shader

2014 年 2 月 21 日

shader简单介绍

wiki上这么描述: shader(着色器)指一组供计算机图形资源在执行渲染任务时使用的指令. shader是render的一部分, 运行在GPU上, 负责计算目标颜色. OpenGL从1.5开始继承一种类C的着色语言, 称为OpenGL Shader Language.


【笔记】ejoy2d —— ppm 和 texture

2004 年 2 月 5 日

ejoy2d 是 ejoy 公司开源的 2d 图像引擎,主要作者是业界牛人云风.

ppm贴图


【笔记】ejoy2d —— matrix

2014 年 1 月 25 日

ejoy2d 是 ejoy 公司开源的 2d 图像引擎,主要作者是业界牛人云风.

矩阵理论基础


【笔记】手游运营听课笔记

学习的来源: 之前听过同事的一次分享, 介绍了某款月流水上5kw的游戏(IOS + Android + Web)运营经验, 重新整理一下当初做的笔记.

上线前期的准备

Android 上按渠道做测试, 一直调整数据到 DAU 和 ARPU 都满意为止.(IOS 太封闭, 不适合测试).

先上 IOS 付费榜: 2k 左右的下载, 即可冲到榜单.


OAuth 协议详解

OAuth 简介

官网上的介绍:

An open protocol to allow secure authorization in a simple and standard method from web, mobile and desktop applications


【笔记】抽象泄漏

这篇文章源自Joel Spolsky, 我看的是中译文版本

一个例子: TCP试图提供一个完整的抽象机制, 想隐藏底下不可靠的网络, 但是很难做到完备, 有时候网络会渗漏越过抽象机制, 比方说网线断了, 又或者网卡超负载了.

结论: All non-trivial abstractions, to some degree, are leaky. 即 所有重大抽象必有泄漏.

再列举一些证明:


【笔记】高性能服务器设计

阅读原文: High Performance Server Architecture

数据拷贝(data copies)

有些数据拷贝隐藏的很深, 经常被忽略. 避免数据拷贝, 最有效的方法是用间接引用, 例如使用指针或者 buffer 的下标.


集线器、交换机和路由器

集线器, 又叫做 hub, 工作在 OSI 七层模型第二层的一个设备, 它传输的数据是以太帧. hub 是一个共享设备, 提供信号放大和中转功能, 通过 hub 转发出去的数据, 实际上是广播给接在同一 hub 下的其他所有节点, 只有目标节点会回复数据. 因此, hub 也是一个共享设备, 有广播风暴的潜在危险.

交换机, 即 switch, 相比集线器则上流了许多. switch 同样工作在第二层(不考虑三层和四层交换机, 那些太高大上), 它不同于 hub 的是: 它可以“学习” MAC 地址, 并把其存放在内部地址表中, 通过在以太帧的 src 和 dst 之间建立临时的交换路径, 使数据帧直接由 src 到达 dst, 所以是一对一的通信, 而不会像 hub 一样产生广播风暴.

一个不是那么形象的比喻: hub 是十字路口, 而 switch 是立交桥.

路由器, 即 router, 工作在第三层, 它传输的数据是 IP 报文, 转发数据的依据是 IP 地址, 能分割广播域(swicth 干不了这事儿, 广播数据还是会在 switch 不同端口的所有物理网段传输). 除此之外, 一般 router 还可以提供防火墙的功能, 可以配 iptables.


makecontext 理解与使用

makecontext 函数镞的定义

#include <ucontext.h>

int getcontext(ucontext_t *ucp);
int setcontext(const ucontext_t *ucp);

void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...);
int swapcontext(ucontext_t *oucp, ucontext_t *ucp);

其中,ucontext 定义如下:


加密与签名算法

背景

1976 年以前, 所有的加密方法都是同一种模式:

  • 甲方选择某一种加密规则, 对信息进行加密.
  • 乙方使用同一种规则, 对信息进行解密.

CMake 使用

2013 年 9 月 12 日

什么是CMake

CMake是一个跨平台的自动化建构系统, 它使用一个名为 CMakeLists.txt 的文件来描述构建过程, 可以产生标准的构建文件, 如 Unix 的 Makefile 或 Windows Visual C++ 的 projects/workspaces. 它的强大之处在于: 跨平台, 自动化.


游戏数据一致性的一点想法

在手游服务器中, 往往会碰到修改其他玩家离线数据的需求, 这个时候如何保证数据的一致性?

数据独占锁

因为多写从而导致数据不一致的概率比较低, 所以这种方法还是可行的, 但是要注意锁的粒度.

乐观锁


Boost 中的智能指针

boost::shared_ptr

boost::shared_ptr 是一个很强大的智能指针封装,它通过一个指针和一个计数器来实现,当计数器的引用数为 0 时,自动析构对象,避免了由于种种原因可能导致的内存泄漏。

线程安全


一致性哈希 Consistant Hash

2013 年 06 月 26 日

在动态变化的 cache 环境中,hash 算法应该满足4个适应算法:

  • balance, 尽量做到负载均衡.

  • monotonicity, 当 cache 节点变化时, 保护已分配的内容不重新 mapping, 当然, 只能是尽量, 因为没有办法完全做到, 不然这个 cache 节点就没有存在的意义了.

  • spread, 当 cache 节点不是完全可见时, 会导致相同的内容 mapping 到不同的节点中去, 这就是 spread, 要尽量避免这种情况.

  • load, 是指每个 cache 节点的负载要尽量低.

大规模的分布式 cache 系统中, key-value 如何做 hash?


HTML5 之 WebSocket

2013 年 6 月 14 日

什么是 WebSocket

WebSocket 是 HTML5 提出的一个协议规范, 参考rfc6455. 不过目前还都是在草案, 没有成为标准, 毕竟 HTML5 还在路上.


手游的登陆流程研究

前言

移动端游戏与传统的端游在登录流程上还是有一些差异性的。

  1. 大部分的偏单机游戏(有联网玩法)的做法是第一次登录时创建昵称,但是不用设置密码,因为用了设备的 id 作为了登录凭证。如果换一个手机,相当于重新创建了个帐号。如果在手机上删除了这个应用,再重新安装,这个有两种选择:一种是重新创建帐号;或者保留原始数据不变(前提是应用的数据文件没有被删除)。

  2. 如果是 MMOG 这种纯网游形式的手游,那基本就和端游没什么区别。第一次进游戏就要求创建帐号,将来登录都是以帐号为依据,因为所有的数据都存于服务器,所以换手机登录,也不受影响。


CPU Cache 学习

CPU Cache 是什么

Small,fast storage used to improve average access time to slow memory.

CPU Cache 的原理


【笔记】 c10K

2013 年 02 月 19 日

写在前面

《The C10K problem》 是十年前的经典文章了, 虽然现在动不动都爱讨论 C100K 乃至 C1000K, 但是经典的东西还是值得回顾.


雪崩与过载保护

2013 年 1 月 28 日

什么是“雪崩”?

这里的"雪崩"是一种形象的比喻, 是指在后台的集群服务中, 由于某一个点不可用(硬件故障, 超出负载能力等), 而扩散到整个集群, 导致整个集群无法服务.


敏感词过滤

2012 年 11 月 25 日

一个简单的敏感词过滤的设计:

  • 最基本的思路是建立hash表来做查询.
  • 敏感词的长度一般不会太长, 一般也就2个汉字(4个字节)左右, 可以再做一份敏感词长度的索引, 这样子在处理时能提高效率.
  • 编码问题: 词库和源因为以往的历史原因, 是 GBK 编码, 而非 UTF.
  • 目前是一个英文忽略大小写的设计.
  • 代码在gbase中, 关键部分的代码如下所示:
// dirty word
typedef struct dirty_t
{
    char word[MAX_DIRTY_WORDS_LEN];
    int prev;
    int next;
} dirty_t;

// dirty context
typedef struct dirty_ctx_t
{
    int table_size;
    dirty_t table[MAX_DIRTY_WORDS_COUNT];
    int hash[MAX_DIRTY_WORDS_HASH_COUNT];
    int index[256][256];
} dirty_ctx_t;

// if > 0x80, means double bytes
// else, single byte
const uint8_t GB_SPEC_CHAR = (uint8_t)(0x80);

// dirty words check
int dirty_check(dirty_ctx_t* ctx, const char* src, int len)
{
    static char lowcase[MAX_SOURCE_WORDS_LEN];
    int i, k, step, key;
    const uint8_t* from;

    if (!ctx || !src || len > MAX_SOURCE_WORDS_LEN) {
        return -3;
    }
    for (i = 0; i < len; i++) {
        lowcase[i] = tolower(src[i]);
    }

    for (i = 0, step = 0; i < len; i += step) {
        key = 0;
        from = (const uint8_t*)&lowcase[i];
        if (from[0] < GB_SPEC_CHAR) {
            key = ctx->index[0][from[0]];
            step = 1;
        } else if (i + 1 < len) {
            key = ctx->index[from[0]][from[1]];
            step = 2;
        } else {
            printf("source code error\n");
            return -2;
        }
        // no index, go ahead
        if (0 == key) {
            continue;
        }
        // found key
        for (k = 1; k < MAX_DIRTY_WORDS_LEN; k++) {
            // exceed len
            if (i + k > len) {
                break;
            }
            // no dirty
            if (0 == CHECK_DIRTY_FLAG(key, k)) {
                continue;
            }
            if (0 == dirty_hash_find(ctx, (const char*)from, k)) {
                return -1;
            }
            // no need to loop all
            RESET_DIRTY_FLAG(key, k);
            if (0 == key) {
                break;
            }
        }
    }
    return 0;
}

字符编码简述

##基本概念

计算机存储的是二进制数据, 0/1 组成的比特, 我们在屏幕上看到的各种显示字符, 包括字母, 汉字, 数字, 各种符号等等, 都是由一串二进制比特转码之后得到的. 这种转码的规则就叫做字符编码. 例如最常见的 ASCII 规则: 字母'A': 对应二进制 0x41, 101000001.

##ASCII


TCP 状态

2012 年 8 月 14 日

TCP的流转状态图

一图胜万言, 先看一下来自 UPN 的一张图:


epoll 的一些使用细节

如果事件 fd 被注册到多个 epoll 中, 事件发生发生时, 每个 epoll 都能触发.

如果注册到 epoll 的 fd 被关闭, 会被自动清除出 epoll, 即不需要 epoll_ctl EPOLL_CTL_DEL.

epoll_wait() 会一直监听 epollhup 事件, 即不需要手工添加 EPOLLHUP events.

为了避免大量 IO 时, ET 模式下 fd 被饿死的情况, Linux 下建议在拥有 fd 的数据结构中增加 ready 位, epoll_wait() 触发事件后仅做置位, 在消费者线程中轮询置位的 fd 列表处理, 即朴素的生产者-消费者模型.


Makefile 变量定义

参考来源: Makefile中的变量

foo = $(bar)

这是最简单的一种变量定义方式, 会在8引用时展开*.

优点是可以引用后面定义的变量.


游戏主循环逻辑

最简单的情况

bool game_is_running = true;
while(game_is_running)
{
  update_game();    // 逻辑帧
  display_game();    // 渲染帧
}

带来的问题:小霸王机器会跑的很慢,牛逼机器上跑得飞快,CPU 达到 100%。显然不是一个合适的算法。


C/C++ 中的异常处理

setjmp in C

在 Mac OS 开发环境下,man setjmp 可以看到setjmp函数簇的定义和说明:

#include <setjmp.h>

void _longjmp(jmp_buf env, int val);
int _setjmp(jmp_buf env);

void longjmp(jmp_buf env, int val);
void longjmperror(void);
int setjmp(jmp_buf env);

void siglongjmp(sigjmp_buf env, int val);
int sigsetjmp(sigjmp_buf env, int savemask);

浮点数存储格式

浮点数保存的字节格式如下:

地址 +0 +1 +2 +3
内容 SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM
  • S 代表符号位,1 是负,0 是正
  • E 偏移 127 的幂,二进制阶码=(EEEEEEEE)-127。
  • M 24位的尾数保存在23位中,只存储23位,最高位固定为1。此方法用最较少的位数实现了较高的有效位数,提高了精度。

零是一个特定值,幂是0, 尾数也是0。


Linux coredump

关于 coredump

在 Linux 下, 如果程序崩溃, OS 可以生成 core 文件保存当前的堆栈信息, 方便 debug.

一般生成 coredump 的原因包括了: