以太坊的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