背景
geth是以太坊官方的golang版本的客户端,代码简洁,结构精妙,是学习golang的好素材。 第一次读geth代码,是2017年,在连连数字研究院时候,带着对go的零基础,带着区块链之热,看得比较支离破碎。 而今4年过去,工作地方从杭州、上海,到了南洋新加坡。重读geth,一是了解geth最新进展,二是也加深对golang的理解,因为现在工作正好用到golang。 想起来了一首词,可以作为当前心境的一种注解。
少年听雨歌楼上,红烛昏罗帐。
壮年听雨客舟中,江阔云低,断雁叫西风。
而今听雨僧庐下,鬓已星星也。
悲欢离合总无情,一任阶前点滴到天明。
重读评论:
比如 geth源码解读1:p2p通讯.md
1. 选了一个好的切入点,因为geth神奇的第一步就是去中心化,带来的问题是怎么找到网络环境差别很大的其他节点?
这个技术互联网用不上,但是对p2p客户端很重要 互联网模式不同,服务器-客户端模式,服务器不需要反向主动连客户端 从这点看技术视角很重要,读代码要有一个好的切入点。
2. 初读的问题是对golang还不熟悉,看某个模块,有点“蜻蜓点水”,自己心中还没有模式,所以看代码有点支离破碎,“见木不见林”
还是p2p为例子,其实现在go代码写多了,知道最重要先看interface,在看不同struct对其实现,思考为什么要这样抽象
nat,geth客户端扮演了upnp的客户端,发出通用的协议,在家用路由器上可以看到注册的upnp端口(也就是在路由器统一ip地址上开了端口,打了个洞)
p2p包-》nat子包
以上我论述存在偏差,因为只看到了upnp,其实节点情况还有ExtIP,还有pmp
3. 快速读代码能力
其实nat包下面代码文件不多,现在我知道了,先筛掉test文件,在看命名最简短的总括文件,interface一般在那里,然后看不同实现 最后找场景,看哪种情况用哪种实现
type Interface interface {
//protocol:tcp or udp; mapping is a port on the local machine map to the router
AddMapping(protocol string, extport, intport int, name string, lifetime time.Duration) error --核心目的还是在公网暴露
DeleteMapping(protocol string, extport, intport int) error
ExternalIP() (net.IP, error)
String() string
}
四种实现
4. 当时没有发现一些精妙之处
比如 端口映射的定时刷新,golang用了timer,刷新其实是个单向的chan,到点涌出消息,这个比java自己的实现要好太多,比C也方便很多,所以golang能够火是有理由的 go语言chan的实现原理.md
重要心得,如何快速读代码?
这2次读代码的遭遇的前后对比,我觉得读代码最重要的是“胸有成竹”,带着预见性去读代码。 比如如上四种实现中,我看到接口,就猜测ExtIP的实现一定很简单,因为已经达到了暴露公网的目的,很可能只是个dummy,后来看下去,果然:
其他两种(Upnp&PMP)实现就复杂了,注意doit函数,是一个发现对方设备的过程
func startautodisc(what string, doit func() Interface) Interface {
// TODO: monitor network configuration and rerun doit when it changes.
return &autodisc{what: what, doit: doit}
}
AddMapping 本身简单,就是等发现,发现后加入map,发现过程复杂,被抽象成函数,Upnp&PMP可能还有不同的版本
所以读代码有点像佛教里面的“以行证信”,你心里已经有很清晰的印象了,读的过程是对你所信的一个验证的过程。如果初读还是很模糊,我建议是暂停读,做些准备活动,把对golang的理解,对业务的理解提升上来再去读,才能达到事半功倍的效果。
|