github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/simulations/examples/ping-pong.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2017 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 package main 26 27 import ( 28 "flag" 29 "fmt" 30 "io/ioutil" 31 "net/http" 32 "os" 33 "sync/atomic" 34 "time" 35 36 "github.com/ethereum/go-ethereum/log" 37 "github.com/ethereum/go-ethereum/node" 38 "github.com/ethereum/go-ethereum/p2p" 39 "github.com/ethereum/go-ethereum/p2p/discover" 40 "github.com/ethereum/go-ethereum/p2p/simulations" 41 "github.com/ethereum/go-ethereum/p2p/simulations/adapters" 42 "github.com/ethereum/go-ethereum/rpc" 43 ) 44 45 var adapterType = flag.String("adapter", "sim", `node adapter to use (one of "sim", "exec" or "docker")`) 46 47 //main()启动一个模拟网络,其中包含运行简单 48 //乒乓协议 49 func main() { 50 flag.Parse() 51 52 //将日志级别设置为跟踪 53 log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(false)))) 54 55 //注册单个乒乓球服务 56 services := map[string]adapters.ServiceFunc{ 57 "ping-pong": func(ctx *adapters.ServiceContext) (node.Service, error) { 58 return newPingPongService(ctx.Config.ID), nil 59 }, 60 } 61 adapters.RegisterServices(services) 62 63 //创建节点适配器 64 var adapter adapters.NodeAdapter 65 66 switch *adapterType { 67 68 case "sim": 69 log.Info("using sim adapter") 70 adapter = adapters.NewSimAdapter(services) 71 72 case "exec": 73 tmpdir, err := ioutil.TempDir("", "p2p-example") 74 if err != nil { 75 log.Crit("error creating temp dir", "err", err) 76 } 77 defer os.RemoveAll(tmpdir) 78 log.Info("using exec adapter", "tmpdir", tmpdir) 79 adapter = adapters.NewExecAdapter(tmpdir) 80 81 case "docker": 82 log.Info("using docker adapter") 83 var err error 84 adapter, err = adapters.NewDockerAdapter() 85 if err != nil { 86 log.Crit("error creating docker adapter", "err", err) 87 } 88 89 default: 90 log.Crit(fmt.Sprintf("unknown node adapter %q", *adapterType)) 91 } 92 93 //启动HTTP API 94 log.Info("starting simulation server on 0.0.0.0:8888...") 95 network := simulations.NewNetwork(adapter, &simulations.NetworkConfig{ 96 DefaultService: "ping-pong", 97 }) 98 if err := http.ListenAndServe(":8888", simulations.NewServer(network)); err != nil { 99 log.Crit("error starting simulation server", "err", err) 100 } 101 } 102 103 //PingpongService在每个节点之间运行一个乒乓协议 104 //每隔10秒向所有连接的对等机发送一次ping,并接收一个pong-in 105 //返回 106 type pingPongService struct { 107 id discover.NodeID 108 log log.Logger 109 received int64 110 } 111 112 func newPingPongService(id discover.NodeID) *pingPongService { 113 return &pingPongService{ 114 id: id, 115 log: log.New("node.id", id), 116 } 117 } 118 119 func (p *pingPongService) Protocols() []p2p.Protocol { 120 return []p2p.Protocol{{ 121 Name: "ping-pong", 122 Version: 1, 123 Length: 2, 124 Run: p.Run, 125 NodeInfo: p.Info, 126 }} 127 } 128 129 func (p *pingPongService) APIs() []rpc.API { 130 return nil 131 } 132 133 func (p *pingPongService) Start(server *p2p.Server) error { 134 p.log.Info("ping-pong service starting") 135 return nil 136 } 137 138 func (p *pingPongService) Stop() error { 139 p.log.Info("ping-pong service stopping") 140 return nil 141 } 142 143 func (p *pingPongService) Info() interface{} { 144 return struct { 145 Received int64 `json:"received"` 146 }{ 147 atomic.LoadInt64(&p.received), 148 } 149 } 150 151 const ( 152 pingMsgCode = iota 153 pongMsgCode 154 ) 155 156 //run实现向对等端发送ping消息的乒乓协议 157 //每隔10秒,并用pong消息响应ping。 158 func (p *pingPongService) Run(peer *p2p.Peer, rw p2p.MsgReadWriter) error { 159 log := p.log.New("peer.id", peer.ID()) 160 161 errC := make(chan error) 162 go func() { 163 for range time.Tick(10 * time.Second) { 164 log.Info("sending ping") 165 if err := p2p.Send(rw, pingMsgCode, "PING"); err != nil { 166 errC <- err 167 return 168 } 169 } 170 }() 171 go func() { 172 for { 173 msg, err := rw.ReadMsg() 174 if err != nil { 175 errC <- err 176 return 177 } 178 payload, err := ioutil.ReadAll(msg.Payload) 179 if err != nil { 180 errC <- err 181 return 182 } 183 log.Info("received message", "msg.code", msg.Code, "msg.payload", string(payload)) 184 atomic.AddInt64(&p.received, 1) 185 if msg.Code == pingMsgCode { 186 log.Info("sending pong") 187 go p2p.Send(rw, pongMsgCode, "PONG") 188 } 189 } 190 }() 191 return <-errC 192 }