兄弟連區塊鏈入門教程eth源碼分析p2p-udp.go源碼分析(一)

來源:互聯網
上載者:User

標籤:dispatch   contain   app   out   cat   private   mat   for   repr   

兄弟連區塊鏈入門教程eth源碼分析p2p-udp.go源碼分析(一)
p2p的網路發現協議使用了Kademlia protocol 來處理網路的節點發現。節點尋找和節點更新。Kademlia protocol使用了UDP協議來進行網路通訊。
閱讀這部分的代碼建議先看看references裡面的Kademlia協議簡介來看看什麼是Kademlia協議。
首先看看資料結構。 網路傳輸了4種資料包(UDP協議是基於報文的協議。傳輸的是一個一個資料包),分別是

ping,pong,findnode和neighbors。 下面分別定義了4種報文的格式。    // RPC packet types    const (        pingPacket = iota + 1 // zero is ‘reserved‘        pongPacket        findnodePacket        neighborsPacket    )    // RPC request structures    type (        ping struct {            Version uint //協議版本            From, To rpcEndpoint      //源IP地址 目的IP地址            Expiration uint64           //逾時時間            // Ignore additional fields (for forward compatibility).            //可以忽略的欄位。 為了向前相容            Rest []rlp.RawValue `rlp:"tail"`        }``        // pong is the reply to ping.        // ping包的回應        pong struct {            // This field should mirror the UDP envelope address            // of the ping packet, which provides a way to discover the            // the external address (after NAT).            // 目的IP地址            To rpcEndpoint            // 說明這個pong包是回應那個ping包的。 包含了ping包的hash值            ReplyTok []byte // This contains the hash of the ping packet.            //包逾時的絕對時間。 如果收到包的時候超過了這個時間,那麼包被認為是逾時的。            Expiration uint64 // Absolute timestamp at which the packet becomes invalid.            // Ignore additional fields (for forward compatibility).            Rest []rlp.RawValue `rlp:"tail"`        }        // findnode 是用來查詢距離target比較近的節點        // findnode is a query for nodes close to the given target.        findnode struct {            // 目的節點            Target NodeID // doesn‘t need to be an actual public key            Expiration uint64            // Ignore additional fields (for forward compatibility).            Rest []rlp.RawValue `rlp:"tail"`        }        // reply to findnode        // findnode的回應        neighbors struct {            //距離target比較近的節點值。            Nodes []rpcNode            Expiration uint64            // Ignore additional fields (for forward compatibility).            Rest []rlp.RawValue `rlp:"tail"`        }        rpcNode struct {            IP net.IP // len 4 for IPv4 or 16 for IPv6            UDP uint16 // for discovery protocol            TCP uint16 // for RLPx protocol            ID NodeID        }        rpcEndpoint struct {            IP net.IP // len 4 for IPv4 or 16 for IPv6            UDP uint16 // for discovery protocol            TCP uint16 // for RLPx protocol        }    )定義了兩個介面類型,packet介面類型應該是給4種不同類型的包指派不同的handle方法。 conn介面定義了一個udp的串連的功能。    type packet interface {        handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error        name() string    }    type conn interface {        ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error)        WriteToUDP(b []byte, addr *net.UDPAddr) (n int, err error)        Close() error        LocalAddr() net.Addr    }udp的結構, 需要注意的是最後一個欄位*Table是go裡面的匿名欄位。 也就是說udp可以直接調用匿名欄位Table的方法。    // udp implements the RPC protocol.    type udp struct {        conn conn                    //網路連接        netrestrict *netutil.Netlist        priv *ecdsa.PrivateKey       //私密金鑰,自己的ID是通過這個來產生的。        ourEndpoint rpcEndpoint        addpending chan *pending            //用來申請一個pending        gotreply chan reply               //用來擷取回應的隊列        closing chan struct{}               //用來關閉的隊列        nat nat.Interface                       *Table    }pending 和reply 結構。 這兩個結構使用者內部的go routine之間進行通訊的結構體。    // pending represents a pending reply.    // some implementations of the protocol wish to send more than one    // reply packet to findnode. in general, any neighbors packet cannot    // be matched up with a specific findnode packet.    // our implementation handles this by storing a callback function for    // each pending reply. incoming packets from a node are dispatched    // to all the callback functions for that node.    // pending結構 代表正在等待一個reply    // 我們通過為每一個pending reply 儲存一個callback來實現這個功能。從一個節點來的所有資料包都會分配到這個節點對應的callback上面。    type pending struct {        // these fields must match in the reply.        from NodeID        ptype byte        // time when the request must complete        deadline time.Time        // callback is called when a matching reply arrives. if it returns        // true, the callback is removed from the pending reply queue.        // if it returns false, the reply is considered incomplete and        // the callback will be invoked again for the next matching reply.        //如果傳回值是true。那麼callback會從隊列裡面移除。 如果返回false,那麼認為reply還沒有完成,會繼續等待下一次reply.        callback func(resp interface{}) (done bool)        // errc receives nil when the callback indicates completion or an        // error if no further reply is received within the timeout.        errc chan<- error    }    type reply struct {        from NodeID        ptype byte        data interface{}        // loop indicates whether there was        // a matching request by sending on this channel.        //通過往這個channel上面發送訊息來表示匹配到一個請求。        matched chan<- bool    }UDP的建立    // ListenUDP returns a new table that listens for UDP packets on laddr.    func ListenUDP(priv *ecdsa.PrivateKey, laddr string, natm nat.Interface, nodeDBPath string, netrestrict *netutil.Netlist) (*Table, error) {        addr, err := net.ResolveUDPAddr("udp", laddr)        if err != nil {            return nil, err        }        conn, err := net.ListenUDP("udp", addr)        if err != nil {            return nil, err        }        tab, _, err := newUDP(priv, conn, natm, nodeDBPath, netrestrict)        if err != nil {            return nil, err        }        log.Info("UDP listener up", "self", tab.self)        return tab, nil    }    func newUDP(priv *ecdsa.PrivateKey, c conn, natm nat.Interface, nodeDBPath string, netrestrict *netutil.Netlist) (*Table, *udp, error) {        udp := &udp{            conn: c,            priv: priv,            netrestrict: netrestrict,            closing: make(chan struct{}),            gotreply: make(chan reply),            addpending: make(chan *pending),        }        realaddr := c.LocalAddr().(*net.UDPAddr)        if natm != nil { //natm nat mapping 用來擷取外網地址            if !realaddr.IP.IsLoopback() { //如果地址是本地迴路位址                go nat.Map(natm, udp.closing, "udp", realaddr.Port, realaddr.Port, "ethereum discovery")            }            // TODO: react to external IP changes over time.            if ext, err := natm.ExternalIP(); err == nil {                realaddr = &net.UDPAddr{IP: ext, Port: realaddr.Port}            }        }        // TODO: separate TCP port        udp.ourEndpoint = makeEndpoint(realaddr, uint16(realaddr.Port))        //建立一個table 後續會介紹。 Kademlia的主要邏輯在這個類裡面實現。        tab, err := newTable(udp, PubkeyID(&priv.PublicKey), realaddr, nodeDBPath)        if err != nil {            return nil, nil, err        }        udp.Table = tab //匿名欄位的賦值        go udp.loop()       //go routine        go udp.readLoop()   //用來網路資料讀取。        return udp.Table, udp, nil    }

兄弟連區塊鏈入門教程eth源碼分析p2p-udp.go源碼分析(一)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.