以太坊的peer to peer (go-ethereum/p2p)模塊可以讓你便捷地在p2p網絡上開發任何應用。這個p2p 包採用現代化的模塊設計,可以很容易地在其之上擴展本身的額外通訊協議。node
開始一個p2p服務須要你先從構造一個p2p.Server{}
實例開始:git
import "github.com/ethereum/go-ethereum/crypto" import "github.com/ethereum/go-ethereum/p2p" nodekey, _ := crypto.GenerateKey() srv := p2p.Server{ MaxPeers: 10, PrivateKey: nodekey, Name: "my node name", ListenAddr: ":30300", Protocols: []p2p.Protocol{}, } srv.Start()
若是你想要在該網絡上擴展本身的協議,你須要在p2p.Protocol{}
中傳入一個子協議:github
func MyProtocol() p2p.Protocol { return p2p.Protocol{ // 1. Name: "MyProtocol", // 2. Version: 1, // 3. Length: 1, // 4. Run: func(peer *p2p.Peer, ws p2p.MsgReadWriter) error { return nil }, // 5. } }
Protocol{}
每次一個可以處理該協議的Peer 發起鏈接時會用到該對象;message
(詳見下文);peer
變量是指代鏈接到當前節點,其攜帶了一些peer自己的信息。其ws
變量是reader和writer容許你同該peer進行通訊,若是信息可以發送到當前節點,則反之也可以從本節點發送到對端peer節點。如今讓咱們將前面留空的handler代碼實現,以讓它可以同別的peer通訊:網絡
const messageId = 0 // 1. type Message string // 2. func msgHandler(peer *p2p.Peer, ws p2p.MsgReadWriter) error { for { msg, err := ws.ReadMsg() // 3. if err != nil { // 4. return err // if reading fails return err which will disconnect the peer. } var myMessage [1]Message err = msg.Decode(&myMessage) // 5. if err != nil { // handle decode error continue } switch myMessage[0] { case "foo": err := p2p.SendItems(ws, messageId, "bar") // 6. if err != nil { return err // return (and disconnect) error if writing fails. } default: fmt.Println("recv:", myMessage) } } return nil }
ReadMsg
將一直阻塞等待,直到其收到了一條新的信息,一個錯誤或者EOF
;msg
包括兩個屬性和一個decode方法工具
Code
包括了信息ID,Code == messageId
(i.e.0)Payload
是信息的內容Decode(<ptr>)
是一個工具方法:取得 msg.Payload
並將其解碼,並將其內容設置到傳入的message指針中,若是失敗了則返回一個errorfoo
將發回一個NewMessage
並用messageId
標記信息類型,信息內容是bar
;而bar
信息在被對端收到以後將被default
case捕獲。如今,咱們將上述的全部部分整合起來,獲得下面的p2p樣例代碼:設計
package main import ( "fmt" "os" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p" ) const messageId = 0 type Message string func MyProtocol() p2p.Protocol { return p2p.Protocol{ Name: "MyProtocol", Version: 1, Length: 1, Run: msgHandler, } } func main() { nodekey, _ := crypto.GenerateKey() srv := p2p.Server{ MaxPeers: 10, PrivateKey: nodekey, Name: "my node name", ListenAddr: ":30300", Protocols: []p2p.Protocol{MyProtocol()}, } if err := srv.Start(); err != nil { fmt.Println(err) os.Exit(1) } select {} } func msgHandler(peer *p2p.Peer, ws p2p.MsgReadWriter) error { for { msg, err := ws.ReadMsg() if err != nil { return err } var myMessage Message err = msg.Decode(&myMessage) if err != nil { // handle decode error continue } switch myMessage { case "foo": err := p2p.SendItems(ws, messageId, "bar")) if err != nil { return err } default: fmt.Println("recv:", myMessage) } } return nil }
原文: Peer to Peer指針
未經容許不得轉載。code