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