精通Filecoin:Filecoin 源码之 Hello 协议

  • 调用 Host 对象的网络对象(即 swarm 对象)的 Notify
    方法,把自身作为被通知者注册到网络对象上。

    h.Network().Notify((*helloNotify)(hello))

    在这一步,通过调用 host
    对象的 Network
    方法,返回底层的 swarm 对象,然后把 hello
    对象转化为 helloNotify
    对象,最后调用 swarm 对象的 Notify
    方法,从而当底层的 swarm 对象有任何事件发生时都会通知 helloNotify
    对象(即 hello
    对象)。
    在 Hello 协议中我们只关心建立连接事件,所以 helloNotify
    类型只实现了这个方法,其他方法都为空实现,具体如下:

    type helloNotify Handler
    func (hn *helloNotify) hello() *Handler {
        return (*Handler)(hn)
    }
    const helloTimeout = time.Second * 10
    func (hn *helloNotify) Connected(n net.Network, c net.Conn) {
        go func() {
            ctx, cancel := context.WithTimeout(context.Background(), helloTimeout)
            defer cancel()
            p := c.RemotePeer()
            if err := hn.hello().sayHello(ctx, p); err != nil {
                log.Warningf("failed to send hello handshake to peer %s: %s", p, err)
            }
        }()
    }

    当节点作为客户端,拨号连接到远程对等节点时,底层的 swarm 对象会调用自身的 notifyAll
    方法,通知所有的 Notify 对象有连接被打开,即调用所有 Notify 对象的 Connected
    方法,包括前面我们注册的通知对象。当调用 helloNotify
    对象的 Connected
    方法时,这个方法内部调用自身的 hello
    方法,后者返回自身并强制转化为 Handler
    类型,然后调用它的 sayHello
    方法,对我们当前连接的远程进行打招呼。
    与此同时,当远程节点作为服务器,接收到我们发送的连接请求生成连接时,它的 swarm 对象也会通知它的所有 Notify 对象,从而也会它的前面注册的通知对象,即调用服务器商的 Connected
    方法,从而调用它的 sayHello
    方法向我们发送它的区块情况;因为第二步中,我们把 Hello 对象的 handleNewStream
    方法注册为 Hello 协议的处理器,所以当节点接收到远程节点发送区块情况时,就会调用这个方法进行处理,这个方法又会调用调用全节点的 syncCallBack
    方法进行区块同步处理。