github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/p2p/simulations/examples/ping-pong.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:41</date> 10 //</624450106870992896> 11 12 13 package main 14 15 import ( 16 "flag" 17 "fmt" 18 "io/ioutil" 19 "net/http" 20 "os" 21 "sync/atomic" 22 "time" 23 24 "github.com/ethereum/go-ethereum/log" 25 "github.com/ethereum/go-ethereum/node" 26 "github.com/ethereum/go-ethereum/p2p" 27 "github.com/ethereum/go-ethereum/p2p/enode" 28 "github.com/ethereum/go-ethereum/p2p/simulations" 29 "github.com/ethereum/go-ethereum/p2p/simulations/adapters" 30 "github.com/ethereum/go-ethereum/rpc" 31 ) 32 33 var adapterType = flag.String("adapter", "sim", `node adapter to use (one of "sim", "exec" or "docker")`) 34 35 //main()启动一个模拟网络,其中包含运行简单 36 //乒乓协议 37 func main() { 38 flag.Parse() 39 40 //将日志级别设置为跟踪 41 log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(false)))) 42 43 //注册单个乒乓球服务 44 services := map[string]adapters.ServiceFunc{ 45 "ping-pong": func(ctx *adapters.ServiceContext) (node.Service, error) { 46 return newPingPongService(ctx.Config.ID), nil 47 }, 48 } 49 adapters.RegisterServices(services) 50 51 //创建节点适配器 52 var adapter adapters.NodeAdapter 53 54 switch *adapterType { 55 56 case "sim": 57 log.Info("using sim adapter") 58 adapter = adapters.NewSimAdapter(services) 59 60 case "exec": 61 tmpdir, err := ioutil.TempDir("", "p2p-example") 62 if err != nil { 63 log.Crit("error creating temp dir", "err", err) 64 } 65 defer os.RemoveAll(tmpdir) 66 log.Info("using exec adapter", "tmpdir", tmpdir) 67 adapter = adapters.NewExecAdapter(tmpdir) 68 69 default: 70 log.Crit(fmt.Sprintf("unknown node adapter %q", *adapterType)) 71 } 72 73 //启动HTTP API 74 log.Info("starting simulation server on 0.0.0.0:8888...") 75 network := simulations.NewNetwork(adapter, &simulations.NetworkConfig{ 76 DefaultService: "ping-pong", 77 }) 78 if err := http.ListenAndServe(":8888", simulations.NewServer(network)); err != nil { 79 log.Crit("error starting simulation server", "err", err) 80 } 81 } 82 83 //PingpongService在每个节点之间运行一个乒乓协议 84 //每隔10秒向所有连接的对等机发送一次ping,并接收一个pong-in 85 //返回 86 type pingPongService struct { 87 id enode.ID 88 log log.Logger 89 received int64 90 } 91 92 func newPingPongService(id enode.ID) *pingPongService { 93 return &pingPongService{ 94 id: id, 95 log: log.New("node.id", id), 96 } 97 } 98 99 func (p *pingPongService) Protocols() []p2p.Protocol { 100 return []p2p.Protocol{{ 101 Name: "ping-pong", 102 Version: 1, 103 Length: 2, 104 Run: p.Run, 105 NodeInfo: p.Info, 106 }} 107 } 108 109 func (p *pingPongService) APIs() []rpc.API { 110 return nil 111 } 112 113 func (p *pingPongService) Start(server *p2p.Server) error { 114 p.log.Info("ping-pong service starting") 115 return nil 116 } 117 118 func (p *pingPongService) Stop() error { 119 p.log.Info("ping-pong service stopping") 120 return nil 121 } 122 123 func (p *pingPongService) Info() interface{} { 124 return struct { 125 Received int64 `json:"received"` 126 }{ 127 atomic.LoadInt64(&p.received), 128 } 129 } 130 131 const ( 132 pingMsgCode = iota 133 pongMsgCode 134 ) 135 136 //run实现向对等端发送ping消息的乒乓协议 137 //每隔10秒,并用pong消息响应ping。 138 func (p *pingPongService) Run(peer *p2p.Peer, rw p2p.MsgReadWriter) error { 139 log := p.log.New("peer.id", peer.ID()) 140 141 errC := make(chan error) 142 go func() { 143 for range time.Tick(10 * time.Second) { 144 log.Info("sending ping") 145 if err := p2p.Send(rw, pingMsgCode, "PING"); err != nil { 146 errC <- err 147 return 148 } 149 } 150 }() 151 go func() { 152 for { 153 msg, err := rw.ReadMsg() 154 if err != nil { 155 errC <- err 156 return 157 } 158 payload, err := ioutil.ReadAll(msg.Payload) 159 if err != nil { 160 errC <- err 161 return 162 } 163 log.Info("received message", "msg.code", msg.Code, "msg.payload", string(payload)) 164 atomic.AddInt64(&p.received, 1) 165 if msg.Code == pingMsgCode { 166 log.Info("sending pong") 167 go p2p.Send(rw, pongMsgCode, "PONG") 168 } 169 } 170 }() 171 return <-errC 172 } 173