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  }