Apr 24
这是罗凯同学内部《Go 快速入门》课程第五讲的作业。

第一题:使用 channel 完成打印1000以内的素数

package main

import "fmt"

func prime(c chan<- int) {
    i := 2
    for {
        isPrime := true
        for j := 2; j < i; j += 1 {
            if i % j == 0 {
                isPrime = false
            }
        }
        if isPrime {
            c <- i
        }
        i += 1
    }
}

func main() {
    c := make(chan int)
    go prime(c)
    for {
        p := <-c
        if p >= 1000 {
            break
        }
        fmt.Println(p)
    }
}



第二题:等价二叉查找树,来自 Go tour:https://tour.go-zh.org/concurrency/7

原题使用 tree.New(1) 来生成一个包含10个元素的二叉查找树,简单的实现可以基于这一点,正好从channel里读出10个数字。

以下这个版本的实现更复杂一些,不假定二叉查找树的长度,所以加一个 wrapper,用来 close channel 。

package main

import (
    "fmt"
    "golang.org/x/tour/tree"
)

// Walk 步进 tree t 将所有的值从 tree 发送到 channel ch。
func Walk(t *tree.Tree, ch chan int) {
    if t == nil {
        return
    }
    Walk(t.Left, ch)
    ch <- t.Value
    Walk(t.Right, ch)
}

func WalkWrapper(t *tree.Tree, ch chan int) {
    Walk(t, ch)
    close(ch)
}

// Same 检测树 t1 和 t2 是否含有相同的值。
func Same(t1, t2 *tree.Tree) bool {
    c1 := make(chan int)
    c2 := make(chan int)
    go WalkWrapper(t1, c1)
    go WalkWrapper(t2, c2)
    for {
        v1, ok1 := <-c1
        v2, ok2 := <-c2

        if ok1 == false && ok2 == false {
            return true
        } else if ok1 == false || ok2 == false {
            return false
        } else {
            if v1 != v2 {
                return false
            }
        }
    }
}

func main() {
    t1 := &tree.Tree{&tree.Tree{nil, 1, nil}, 2, &tree.Tree{nil, 3, nil}}
    t2 := &tree.Tree{&tree.Tree{&tree.Tree{nil, 1, nil}, 2, nil}, 3, &tree.Tree{nil, 4, nil}}
    fmt.Println(t1)
    fmt.Println(t2)
    fmt.Println(Same(t1, t2))

    t3 := tree.New(1)
    t4 := tree.New(1)
    fmt.Println(t3)
    fmt.Println(t4)
    fmt.Println(Same(t3, t4))
}
Mar 6

TourDeBabel 不指定

felix021 @ 2019-3-6 11:54 [IT » 其他] 评论(0) , 引用(0) , 阅读(294) | Via 本站原创
转自:https://code.google.com/archive/p/windows-config/wikis/TourDeBabel.wiki
原文:https://sites.google.com/site/steveyegge2/tour-de-babel

(无意中翻出了很多年前看过的这篇文章,发现是在google code上的,那就转载作为存档吧)

通天塔导游

(译注:圣经记载:在远古的时候,人类都使用一种语言,全世界的人决定一起造一座通天的塔,就是巴别塔,后来被上帝知道了,上帝就让人们使用不同的语言,这个塔就没能造起来。 巴别塔不建自毁,与其说上帝的分化将人类的语言复杂化,不如说是人类自身心灵和谐不再的分崩离析。之所以后来有了翻译,不仅是为了加强人类之间的交流,更寄达了一种愿望,希望能以此消除人际的隔阂,获求来自心灵的和谐及慰藉。真正的译者,把握血脉,抚平创痕,通传天籁,开启心门。)

这是我写的旋风式的编程语言简介—我本来为亚马逊开发者杂志本月的期刊写的,但是发现我写的东西没法…见人。

首先,我偶尔一不小心口出脏话,或者对上帝不恭的话,所以对很官方很正式的亚马逊上发表是不合适的; 所以我就把它塞到我的博客里了,我的博客反正没人看的。除了你以外。是的,只有你会看,你好啊。

其次,这是一项进行中的工程,现在只是东打一耙西搞一下,还没有精加工过的。又一个把它写到博客里的很大的理由。不需要很好,或很完整。就是我今天想说的一些话。请随便!

我的旋风式简介会讲C,C++,Lisp,Java,Perl,(我们在亚马逊用到的所有语言),Ruby (我就是喜欢),和Python,把Python加进来是因为—好吧,你看了就知道了,现在我可不说。

C

你必须懂C。为哈? 因为出于所有现实的理由,这个世界上你过去,现在,将来会用到的每一台计算机都是一台冯·诺曼机器,而C是一种轻量级的,很有表达力的语法,能很好的展现冯·诺曼机器的能力。
Nov 23

浏览器客户端证书 不指定

felix021 @ 2018-11-23 23:06 [IT » 其他] 评论(0) , 引用(0) , 阅读(544) | Via 本站原创
2015年,从某传统金融国企跳槽来到我司的时候,发现后台管理系统竟然需要安装客户端证书才能登陆,简直惊为天人,通过利用 https 的客户端认证,配合证书中嵌入的用户名做权限控制,把内部系统的入侵难度至少增加了一个量级(当然,安装证书的过程对于非技术线的同学说也麻烦了不少)。

后来发现,原来是把 github.com/OpenVPN/easy-rsa 这个项目包装了一下实现的,其实也并不是很困难。

今年年初因为新项目也需要这个方案,自己心血来潮,参考网上的一些说明,用 openssl 的 genrsa、req、x509、pkcs12 这几个命令试着自己颁发客户端证书,并且包装了一套脚本,勉强能用。

但当时没有太多时间,吊销的功能并没有做,因为比颁发证书麻烦多了,不只是敲几个命令,还需要一套更复杂的方案,包括维护一个证书信息列表、按一定规范的文件目录结构,以及DIY的 openssh 配置文件等。

最近抽了两个晚上把整个流程重新梳理了一遍,填了几个坑,终于做了一套完整的脚本出来,这才好意思写这篇博客介绍一下。

这套脚本可以在这里获取:

  https://github.com/felix021/openssl-selfsign

使用起来可以说是非常简单了:

1. 创建CA

  $ ./1-sign-site.sh dev.com

会创建 ca 证书,并在 cert/site/dev.com/ 下面创建 *.dev.com 的 https 证书,并且生成一个 nginx.conf 配置文件供参考(直接可以用的)。

2. 颁发客户端证书

  $ ./2-sign-user.sh test1

在 cert/newcerts/test1-01/ 下面创建 test1 用户的一个客户端证书 cert.p12 ,并给出对应的密码,双击按提示导入即可。

3. 参考第一步生成的 nginx.conf 配置文件,配置好 web 服务器,就行了。

4. 稳妥起见,应当在代码中读取 http 头里的 SSL_DN 参数,从中获取邮箱或者用户名来作为系统的用户名。

至于吊销的过程,要更复杂一些,可以参考该项目的 README 。
Feb 28
留档备查

脚本里设置了 ServerActive ,会主动尝试到zabbix server注册,但需要先在zabbix frontend的 configuration->actions->auto registration 配置好 add host 动作,这样才会自动添加。

引用

#!/bin/bash

set -x

ZABBIX_SERVER=192.168.1.100

wget http://repo.zabbix.com/zabbix/3.2/ubuntu/pool/main/z/zabbix-release/zabbix-release_3.2-1+xenial_all.deb
dpkg -i zabbix-release_3.2-1+xenial_all.deb
apt update
apt -y install zabbix-agent

ip=`ifconfig  | grep -o 'inet addr:172\.[0-9.]*' | awk -F: '{print $2}'`
sed -i \
    -e 's/^Server=.*$/Server='$ZABBIX_SERVER'/' \
    -e 's/^ServerActive=.*$/ServerActive=lan.zabbix.thebitplus.com/' \
    -e 's/^Hostname=.*$/Hostname='`hostname`'/' \
    /etc/zabbix/zabbix_agentd.conf

sudo update-rc.d zabbix-agent enable
sudo service zabbix-agent restart

echo "Done"
Feb 11
莫名其妙的一个错误,手头的两个sentry实例里都没有这个表,但是还是会报这个错。

没研究具体的代码,但是通过查找源码里的 sentry_email 发掘了表结构,建表并授权即可:
引用
$ psql -h $HOST -U root -W sentry
sentry=> create extension citext;
CREATE EXTENSION
sentry=> create table sentry_email (id bigserial primary key, email CITEXT, date_added timestamp with time zone);
CREATE TABLE
sentry=> grant all privileges on table sentry_email to sentry;
GRANT
sentry=> GRANT USAGE, SELECT ON SEQUENCE sentry_email_id_seq1 to sentry;
GRANT
Nov 16
与某供应商对接的时候,要求用他们的RSA公钥加密,抛过来一个 RSAUtil.java ,核心代码大概是这样的:

public byte[] encrypt(byte[] data, PublicKey pk) throws Exception {
    Cipher cipher = Cipher.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider());
    cipher.init(Cipher.ENCRYPT_MODE, pk);
    byte[] raw = new byte[128]; //cipher.getBlockSize() = 128
    cipher.doFinal(data, 0, data.length, raw, 0);
    return raw;
}


RSA什么的,用php来做不要太简单,顺手就能写出来:

function rsa_encrypt($plain_text, $public_key_path)
{
    $public_key = openssl_pkey_get_public(file_get_contents($public_key_path));
    openssl_public_encrypt($plain_text, $encrypted, $public_key);
    return bin2hex($encrypted);
}

function rsa_decrypt($encrypted, $private_key_path)
{
    $private_key = openssl_pkey_get_private(file_get_contents($private_key_path));
    openssl_private_decrypt(hex2bin($encrypted), $plain_text, $private_key);
    return $plain_text;
}


结果果然不行,发过去以后,对方表示无法解密,而我没有对方的私钥,不好验证,没办法,只能自己动手,造一对rsa密钥:

引用
$ openssl genrsa -out test.pem 1024
$ openssl rsa -in test.pem -pubout -out test_public.pem


试了下,确实和 java 的结果不互通。不过在测试过程中发现一个现象:java生成的加密串总是一样的,而php生成的加密串总是不一样的。google搜了一下"php openssl_public_encrypt different everytime", Stack Overflow 的解释是,PHP的 openssl_public_encrypt 默认使用 PKCS#1 算法,引入随机数,用于防止流量探测(频率分析、密文匹配什么的,我就不懂了)。

所以很显然,Bouncy Castle 没有使用 PKCS#1 算法,放狗搜到官方文档说,Cipher.getInstance("RSA", "BC") ,第一个参数 RSA 相当于 "RSA/NONE/NoPadding" (当然也可以指定 RSA/NONE/PKCS1Padding )。

看了下 php的openssl_public_encrypt文档,可以给第四个参数“padding”指定不同的值,例如 OPENSSL_NO_PADDING ,但是试了下,发现直接失败了,只好再放狗,竟然搜到了 php的bugreport,还好第一个回复就说明了原因:需要手动用 ASCII 0 填充到 blocksize 才行(当然rsa并不禁止使用其他value,主要是加解密双方要约定好)。

验证了一下,用 OPENSSL_NO_PADDING  能够正常解密 java 生成的密文,并且在明文前面填充了若干 ASCII 0 ,补全到128字节,就此解决问题:

function rsa_encrypt($plain_text, $public_key_path)
{
    $public_key = openssl_pkey_get_public(file_get_contents($public_key_path));
    openssl_public_encrypt(str_pad($plain_text, 128, "\0", STR_PAD_LEFT), $encrypted, $public_key, OPENSSL_NO_PADDING);
    return bin2hex($encrypted);
}

function rsa_decrypt($encrypted, $private_key_path)
{
    $private_key = openssl_pkey_get_private(file_get_contents($private_key_path));
    openssl_private_decrypt(hex2bin($encrypted), $plain_text, $private_key, OPENSSL_NO_PADDING);
    return ltrim($plain_text, "\0");
}


Jul 1

ucloud体验报告 不指定

felix021 @ 2013-7-1 02:02 [IT » 其他] 评论(3) , 引用(0) , 阅读(23498) | Via 本站原创
UPDATE@2013.08.04 搞到了一批折扣邀请码,有兴趣的同学(最好是带项目的团队、公司等)可以联系我。

最近弄了一台 ucloud.cn 的vps。准确地说应该是云主机,跟我在别处买的vps的确是有些不同的地方。

首先是注册,ucloud对密码的安全性要求太高了。其实很早之前就拿到邀请码试用过三天,但是由于对密码的要求过于复杂,刚开始几次,每次登陆之前都得重置密码,比较蛋疼;后来终于记住了,相当不容易。

然后是选配置。ucloud的最低配置是单核、2G内存、2mbps单线,显然不是面向个人vps玩家了,不过对于创业公司什么的倒是很合适。对比了一下国内另外两家云主机的同样配置,价格上也还是挺有优势的。选配置的时候有个“高性能磁盘”选项很有意思,目测是为了数据库之类对磁盘IOPS要求比较高的场合设置的,勾上了价格也没多大变化。

最终我选择的配置是双核、2G、20GB数据盘、4M双线,2700/yr。

开通主机以后就是选择系统。我图省事选了个ubuntu 12.04 64bit的。本来还做好准备像我的个人vps那样,vnc连上去在命令行下通过mount上去的iso安装,结果发现等了一会儿直接就可以开始用了,看起来应该是像openvz方案一样事先准备好了对应的template改改配置就能上。而且非常贴心的一点是,apt的默认源是ucloud自建的同步源,apt-get update和install的时候就很爽~其他的OS没试过,不过去mirror看了下,除了ubuntu,还有debian、fedora、centos等发行版的源,甚至还有个10gen(也就是mongodb他们家)的源。

进入后台管理看了下,一眼就能认出浓浓的bootstrap的味道,感觉挺无趣的,好歹用个Flat UI什么的换换小清新的口味嘛-。-  不过后台功能还是挺赞的,尤其是与 upyun、dnspod 的战略合作,可以绑定他们两家帐号,方便管理。至于upyun/dnspod的牛逼之处就不用多说了,这三家能合力打造这样的平台,前景我非常看好。

开通的时候我选择的是华东双线机房,所以给分配了2个ip,一个电信一个联通,因为域名是托管在dnspod,可以为不同请求线路返回合适的ip,很给力。ping了一下,延迟只有11ms,相当不错。ssh登上去看了下,ifconfig只看到了个内网ip,还觉得挺神奇的。后来在ucloud的主页看到,这是他们的“弹性IP”解决方案,ip不是直接绑定在vps的网卡上。设想,对于线上4台年付费的web机器进行负载均衡,某一台down了,可以马上把另一个按小时付费的备机开起来,把ip切过去,这样即减少了故障时间,又相当节省,貌似不错。

所谓“云主机”,我觉得跟传统vps/服务器的主要区别有2个:一个是可以按需选择合适的配置,并且此后还可以不断调整升级且代价很小;另一个就是底层存储是基于网络的,所在服务器挂掉也不用担心,换个地方再启动起来就好了。

去年12月在杭州参加SegmentFault举办的Hackathon的时候曾经试用过XX云的主机,他们家的特色是有自建的BGP骨干网,网络比较给力;但问题是,XX云主机的磁盘IO烂到一定境界,实在是……后来听说他们是直接用NFS作为底层存储,以及看到各种吐槽他们家IO的……

所以这次用ucloud的时候就特意关注了下磁盘性能,跑点数据列出来附在后面供参考,可以看出性能相当不错,已fio的数据为参考,顺序读取697M,顺序写入419M,随机读取 6245 IOPS,随机写入 309 IOPS。其中随机写入偏弱,可能是多备份网络延迟的原因吧,不知道选择“高性能磁盘”效果会怎样,但是就算是309 IOPS,也比服务器用的机械硬盘快多了,跟别说被甩开n条街的XX云了……很好奇他们家这个是怎么实现的,真希望ucloud的技术团队可以分享一下经验~

至于ucloud的其他方面,因为用的时间还比较短,体验不多,没什么可说的,就是总体感觉良好。ucloud提供的这项服务,对于创业团队什么的来说,的确可以算是最合适的选择了。


下附磁盘测试数据:

TEST#1 dd写入
引用
$ dd if=/dev/zero bs=1M count=4096 of=test
4096+0 records in
4096+0 records out
4294967296 bytes (4.3 GB) copied, 15.1328 s, 284 MB/s


TEST#2 hdparm -tT
引用
$ for i in 1 2 3; do sudo hdparm -tT /dev/vdb; done

/dev/vdb:
Timing cached reads:  9574 MB in  2.00 seconds = 4790.56 MB/sec
Timing buffered disk reads: 1714 MB in  3.02 seconds = 568.37 MB/sec

/dev/vdb:
Timing cached reads:  10018 MB in  2.00 seconds = 5013.55 MB/sec
Timing buffered disk reads: 1840 MB in  3.01 seconds = 611.33 MB/sec

/dev/vdb:
Timing cached reads:  9574 MB in  2.00 seconds = 4792.34 MB/sec
Timing buffered disk reads: 1908 MB in  3.00 seconds = 635.80 MB/sec


TEST #3 fio random-read
引用
$ cat random-read-test.fio   
[random-read]
rw=randread
size=1g
directory=/home/felix021/test/

$ fio random-read-test.fio
random-read: (g=0): rw=randread, bs=4K-4K/4K-4K, ioengine=sync, iodepth=1
fio 1.59
Starting 1 process
random-read: Laying out IO file(s) (1 file(s) / 1024MB)
Jobs: 1 (f=1): [r] [100.0% done] [26789K/0K /s] [6540 /0  iops] [eta 00m:00s]
random-read: (groupid=0, jobs=1): err= 0: pid=10676
  read : io=1024.0MB, bw=24980KB/s, iops=6245 , runt= 41976msec
    clat (usec): min=77 , max=35439 , avg=155.44, stdev=237.39
    lat (usec): min=78 , max=35440 , avg=155.82, stdev=237.39
    bw (KB/s) : min=18384, max=28256, per=100.22%, avg=25035.02, stdev=1702.27
  cpu          : usr=3.42%, sys=23.48%, ctx=262433, majf=0, minf=24
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
    submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
    complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
    issued r/w/d: total=262144/0/0, short=0/0/0
    lat (usec): 100=3.05%, 250=93.84%, 500=2.44%, 750=0.22%, 1000=0.10%
    lat (msec): 2=0.23%, 4=0.07%, 10=0.05%, 20=0.01%, 50=0.01%

Run status group 0 (all jobs):
  READ: io=1024.0MB, aggrb=24980KB/s, minb=25579KB/s, maxb=25579KB/s, mint=41976msec, maxt=41976msec

Disk stats (read/write):
  vdb: ios=260955/11, merge=0/10, ticks=25956/396, in_queue=25972, util=61.22%


TEST #4 fio random-write
$ cat random-write-test.fio
[random-write]
rw=randwrite
size=1G
directory=/home/felix021/test/

$ fio random-write-test.fio
random-write: (g=0): rw=randwrite, bs=4K-4K/4K-4K, ioengine=sync, iodepth=1
fio 1.59
Starting 1 process
random-write: Laying out IO file(s) (1 file(s) / 1024MB)
Jobs: 1 (f=1): [w] [92.5% done] [0K/1429K /s] [0 /348  iops] [eta 01m:09s]
random-write: (groupid=0, jobs=1): err= 0: pid=10733
  write: io=1024.0MB, bw=1236.3KB/s, iops=309 , runt=848202msec
    clat (usec): min=1 , max=1101.4K, avg=3231.07, stdev=10586.16
    lat (usec): min=1 , max=1101.4K, avg=3231.53, stdev=10586.42
    bw (KB/s) : min=  14, max=397248, per=95.34%, avg=1178.40, stdev=9976.63
  cpu          : usr=0.19%, sys=0.75%, ctx=49240, majf=0, minf=24
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
    submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
    complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
    issued r/w/d: total=0/262144/0, short=0/0/0
    lat (usec): 2=0.01%, 4=0.06%, 10=54.82%, 20=25.75%, 50=2.45%
    lat (usec): 100=1.28%, 250=0.84%, 500=0.36%, 750=0.08%, 1000=0.02%
    lat (msec): 2=0.04%, 4=0.05%, 10=0.29%, 20=8.87%, 50=4.58%
    lat (msec): 100=0.47%, 250=0.02%, 500=0.01%, 750=0.01%, 1000=0.01%
    lat (msec): 2000=0.01%

Run status group 0 (all jobs):
  WRITE: io=1024.0MB, aggrb=1236KB/s, minb=1265KB/s, maxb=1265KB/s, mint=848202msec, maxt=848202msec

Disk stats (read/write):
  vdb: ios=1/145156, merge=0/13152, ticks=12/3297360, in_queue=3297220, util=99.78%

TEST #5 fio sequence-read
引用
$ cat read-test.fio
[random-read]
rw=read
size=1g
directory=/home/felix021/test/

$ fio read-test.fio
random-read: (g=0): rw=read, bs=4K-4K/4K-4K, ioengine=sync, iodepth=1
fio 1.59
Starting 1 process
random-read: Laying out IO file(s) (1 file(s) / 1024MB)
Jobs: 1 (f=1)
random-read: (groupid=0, jobs=1): err= 0: pid=10798
  read : io=1024.0MB, bw=697191KB/s, iops=174297 , runt=  1504msec
    clat (usec): min=0 , max=16300 , avg= 4.73, stdev=97.89
    lat (usec): min=1 , max=16300 , avg= 4.95, stdev=97.89
    bw (KB/s) : min=615400, max=779152, per=99.97%, avg=696994.67, stdev=81877.45
  cpu          : usr=11.44%, sys=57.75%, ctx=3787, majf=0, minf=26
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
    submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
    complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
    issued r/w/d: total=262144/0/0, short=0/0/0
    lat (usec): 2=66.20%, 4=31.16%, 10=0.58%, 20=0.15%, 50=0.28%
    lat (usec): 100=0.63%, 250=0.89%, 500=0.07%, 750=0.01%, 1000=0.01%
    lat (msec): 2=0.01%, 4=0.01%, 10=0.01%, 20=0.01%

Run status group 0 (all jobs):
  READ: io=1024.0MB, aggrb=697191KB/s, minb=713924KB/s, maxb=713924KB/s, mint=1504msec, maxt=1504msec

Disk stats (read/write):
  vdb: ios=3697/0, merge=0/0, ticks=1280/0, in_queue=1268, util=74.56%


TEST #6 fio sequence-write
引用
$ cat write-test.fio
[random-read]
rw=write
size=1g
directory=/home/felix021/test/

$ fio write-test.fio
random-read: (g=0): rw=write, bs=4K-4K/4K-4K, ioengine=sync, iodepth=1
fio 1.59
Starting 1 process
Jobs: 1 (f=1): [W] [-.-% done] [0K/409.3M /s] [0 /102K iops] [eta 00m:00s]
random-read: (groupid=0, jobs=1): err= 0: pid=10816
  write: io=1024.0MB, bw=419934KB/s, iops=104983 , runt=  2497msec
    clat (usec): min=0 , max=10136 , avg= 7.71, stdev=123.62
    lat (usec): min=0 , max=10136 , avg= 7.98, stdev=123.64
    bw (KB/s) : min=177498, max=650096, per=110.68%, avg=464776.50, stdev=202324.17
  cpu          : usr=14.74%, sys=57.69%, ctx=199, majf=0, minf=27
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
    submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
    complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
    issued r/w/d: total=0/262144/0, short=0/0/0
    lat (usec): 2=0.08%, 4=36.39%, 10=58.08%, 20=4.91%, 50=0.38%
    lat (usec): 100=0.07%, 250=0.01%, 500=0.01%, 750=0.01%, 1000=0.01%
    lat (msec): 2=0.01%, 4=0.01%, 10=0.04%, 20=0.01%

Run status group 0 (all jobs):
  WRITE: io=1024.0MB, aggrb=419934KB/s, minb=430012KB/s, maxb=430012KB/s, mint=2497msec, maxt=2497msec

Disk stats (read/write):
  vdb: ios=0/1382, merge=0/11, ticks=0/219176, in_queue=246612, util=77.43%

Mar 24
原文: Reed–Solomon codes for coders
参考: AN2407.pdf
WIKI: 里德-所罗门码
实现:Pypi ReedSolo

#译注:最近看到了RS码,发现还挺有意思的,找了一些资料学习了下,发现对于程序员来说,从这篇看起会比较容易。看完以后想着翻译一下试试,看看自己到底看懂了多少,于是就有了这篇。本文有部分错误,以及一些排版不对的地方,有兴趣的还是看原文更好:)

为程序员写的Reed-Solomon码解释

Reed-Solomon纠错码(以下简称RS码)广泛用于数据存储(如CD)和传输应用中。然而,在这些应用中,码字是藏在了电子设备里,所以无法一窥它们的模样以及它们是如何生效的。有些复杂的条形码设计也采用了RS码,能够暴露出所有的细节,对于想要获得这种技术如何生效的第一手技术的爱好者,这是一种很有趣的方式。

在这篇文章里,我是试图从程序员的视角(而不是数学家的视角)来介绍RS码的基本原理。我会用以当下流行的QR码作为例子来介绍。我选择了Python(主要是因为写出来的代码看起来整洁美观),但是我也会介绍一些不那么显而易见的Python特性,以便那些不熟悉Python的人也能看懂。里头涉及到的数学知识对读者有一定要求,并且一般是大学才教授的,但是应当能让对高中代数掌握较好的人看懂。

内容:
1 QR码结构
1.1 掩码
1.2 格式信息
1.3 数据
1.4 解码
2 BCH码
2.1 BCH错误检测
2.2 BCH纠错
3 有限域理论
3.1 乘法
3.2 基于对数的乘法
3.3 除法
3.4 多项式
4 RS码
4.1 RS生成多项式
4.2 RS编码
4.3 伴随式(Syndrome)计算
4.4 消除(erasure)纠正
4.5 错误(error)纠正
4.6 消除和错误纠正
分页: 1/7 第一页 1 2 3 4 5 6 7 下页 最后页 [ 显示模式: 摘要 | 列表 ]