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