github.com/aakash4dev/cometbft@v0.38.2/spec/p2p/legacy-docs/connection.md (about)

     1  # P2P Multiplex Connection
     2  
     3  ## MConnection
     4  
     5  `MConnection` is a multiplex connection that supports multiple independent streams
     6  with distinct quality of service guarantees atop a single TCP connection.
     7  Each stream is known as a `Channel` and each `Channel` has a globally unique _byte id_.
     8  Each `Channel` also has a relative priority that determines the quality of service
     9  of the `Channel` compared to other `Channel`s.
    10  The _byte id_ and the relative priorities of each `Channel` are configured upon
    11  initialization of the connection.
    12  
    13  The `MConnection` supports three packet types:
    14  
    15  - Ping
    16  - Pong
    17  - Msg
    18  
    19  ### Ping and Pong
    20  
    21  The ping and pong messages consist of writing a single byte to the connection; 0x1 and 0x2, respectively.
    22  
    23  When we haven't received any messages on an `MConnection` in time `pingTimeout`, we send a ping message.
    24  When a ping is received on the `MConnection`, a pong is sent in response only if there are no other messages
    25  to send and the peer has not sent us too many pings (TODO).
    26  
    27  If a pong or message is not received in sufficient time after a ping, the peer is disconnected from.
    28  
    29  ### Msg
    30  
    31  Messages in channels are chopped into smaller `msgPacket`s for multiplexing.
    32  
    33  ```go
    34  type msgPacket struct {
    35   ChannelID byte
    36   EOF       byte // 1 means message ends here.
    37   Bytes     []byte
    38  }
    39  ```
    40  
    41  The `msgPacket` is serialized using [Proto3](https://developers.google.com/protocol-buffers/docs/proto3).
    42  The received `Bytes` of a sequential set of packets are appended together
    43  until a packet with `EOF=1` is received, then the complete serialized message
    44  is returned for processing by the `onReceive` function of the corresponding channel.
    45  
    46  ### Multiplexing
    47  
    48  Messages are sent from a single `sendRoutine`, which loops over a select statement and results in the sending
    49  of a ping, a pong, or a batch of data messages. The batch of data messages may include messages from multiple channels.
    50  Message bytes are queued for sending in their respective channel, with each channel holding one unsent message at a time.
    51  Messages are chosen for a batch one at a time from the channel with the lowest ratio of recently sent bytes to channel priority.
    52  
    53  ## Sending Messages
    54  
    55  There are two methods for sending messages:
    56  
    57  ```go
    58  func (m MConnection) Send(chID byte, msg interface{}) bool {}
    59  func (m MConnection) TrySend(chID byte, msg interface{}) bool {}
    60  ```
    61  
    62  `Send(chID, msg)` is a blocking call that waits until `msg` is successfully queued
    63  for the channel with the given id byte `chID`. The message `msg` is serialized
    64  using protobuf marshalling.
    65  
    66  `TrySend(chID, msg)` is a nonblocking call that queues the message msg in the channel
    67  with the given id byte chID if the queue is not full; otherwise it returns false immediately.
    68  
    69  `Send()` and `TrySend()` are also exposed for each `Peer`.
    70  
    71  ## Peer
    72  
    73  Each peer has one `MConnection` instance, and includes other information such as whether the connection
    74  was outbound, whether the connection should be recreated if it closes, various identity information about the node,
    75  and other higher level thread-safe data used by the reactors.
    76  
    77  ## Switch/Reactor
    78  
    79  The `Switch` handles peer connections and exposes an API to receive incoming messages
    80  on `Reactors`. Each `Reactor` is responsible for handling incoming messages of one
    81  or more `Channels`. So while sending outgoing messages is typically performed on the peer,
    82  incoming messages are received on the reactor.
    83  
    84  ```go
    85  // Declare a MyReactor reactor that handles messages on MyChannelID.
    86  type MyReactor struct{}
    87  
    88  func (reactor MyReactor) GetChannels() []*ChannelDescriptor {
    89      return []*ChannelDescriptor{ChannelDescriptor{ID:MyChannelID, Priority: 1}}
    90  }
    91  
    92  func (reactor MyReactor) Receive(chID byte, peer *Peer, msgBytes []byte) {
    93      r, n, err := bytes.NewBuffer(msgBytes), new(int64), new(error)
    94      msgString := ReadString(r, n, err)
    95      fmt.Println(msgString)
    96  }
    97  
    98  // Other Reactor methods omitted for brevity
    99  ...
   100  
   101  switch := NewSwitch([]Reactor{MyReactor{}})
   102  
   103  ...
   104  
   105  // Send a random message to all outbound connections
   106  for _, peer := range switch.Peers().List() {
   107      if peer.IsOutbound() {
   108          peer.Send(MyChannelID, "Here's a random message")
   109      }
   110  }
   111  ```