github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/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 12:09:44</date> 10 //</624342661167321088> 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/discover" 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 case "docker": 70 log.Info("using docker adapter") 71 var err error 72 adapter, err = adapters.NewDockerAdapter() 73 if err != nil { 74 log.Crit("error creating docker adapter", "err", err) 75 } 76 77 default: 78 log.Crit(fmt.Sprintf("unknown node adapter %q", *adapterType)) 79 } 80 81 //启动HTTP API 82 log.Info("starting simulation server on 0.0.0.0:8888...") 83 network := simulations.NewNetwork(adapter, &simulations.NetworkConfig{ 84 DefaultService: "ping-pong", 85 }) 86 if err := http.ListenAndServe(":8888", simulations.NewServer(network)); err != nil { 87 log.Crit("error starting simulation server", "err", err) 88 } 89 } 90 91 //PingpongService在每个节点之间运行一个乒乓协议 92 //每隔10秒向所有连接的对等机发送一次ping,并接收一个pong-in 93 //返回 94 type pingPongService struct { 95 id discover.NodeID 96 log log.Logger 97 received int64 98 } 99 100 func newPingPongService(id discover.NodeID) *pingPongService { 101 return &pingPongService{ 102 id: id, 103 log: log.New("node.id", id), 104 } 105 } 106 107 func (p *pingPongService) Protocols() []p2p.Protocol { 108 return []p2p.Protocol{{ 109 Name: "ping-pong", 110 Version: 1, 111 Length: 2, 112 Run: p.Run, 113 NodeInfo: p.Info, 114 }} 115 } 116 117 func (p *pingPongService) APIs() []rpc.API { 118 return nil 119 } 120 121 func (p *pingPongService) Start(server *p2p.Server) error { 122 p.log.Info("ping-pong service starting") 123 return nil 124 } 125 126 func (p *pingPongService) Stop() error { 127 p.log.Info("ping-pong service stopping") 128 return nil 129 } 130 131 func (p *pingPongService) Info() interface{} { 132 return struct { 133 Received int64 `json:"received"` 134 }{ 135 atomic.LoadInt64(&p.received), 136 } 137 } 138 139 const ( 140 pingMsgCode = iota 141 pongMsgCode 142 ) 143 144 //run实现向对等端发送ping消息的乒乓协议 145 //每隔10秒,并用pong消息响应ping。 146 func (p *pingPongService) Run(peer *p2p.Peer, rw p2p.MsgReadWriter) error { 147 log := p.log.New("peer.id", peer.ID()) 148 149 errC := make(chan error) 150 go func() { 151 for range time.Tick(10 * time.Second) { 152 log.Info("sending ping") 153 if err := p2p.Send(rw, pingMsgCode, "PING"); err != nil { 154 errC <- err 155 return 156 } 157 } 158 }() 159 go func() { 160 for { 161 msg, err := rw.ReadMsg() 162 if err != nil { 163 errC <- err 164 return 165 } 166 payload, err := ioutil.ReadAll(msg.Payload) 167 if err != nil { 168 errC <- err 169 return 170 } 171 log.Info("received message", "msg.code", msg.Code, "msg.payload", string(payload)) 172 atomic.AddInt64(&p.received, 1) 173 if msg.Code == pingMsgCode { 174 log.Info("sending pong") 175 go p2p.Send(rw, pongMsgCode, "PONG") 176 } 177 } 178 }() 179 return <-errC 180 } 181