This commit is contained in:
Jae Kwon 2014-12-23 19:31:24 -08:00
parent bff93107ef
commit fa7c83166f
8 changed files with 105 additions and 61 deletions

View File

@ -1,35 +1,77 @@
# P2P Module
# `tendermint/p2p`
P2P provides an abstraction around peer-to-peer communication.<br/>
Communication happens via Reactors that react to messages from peers.<br/>
Each Reactor has one or more Channels of communication for each Peer.<br/>
Channels are multiplexed automatically and can be configured.<br/>
A Switch is started upon app start, and handles Peer management.<br/>
A PEXReactor implementation is provided to automate peer discovery.<br/>
`tendermint/p2p` provides an abstraction around peer-to-peer communication.<br/>
## Channels
## Peer/MConnection/Channel
Each peer connection is multiplexed into channels.
The p2p module comes with a channel implementation used for peer
discovery (called PEX, short for "peer exchange").
Each peer has one `MConnection` (multiplex connection) instance.
<table>
<tr>
<td><b>Channel</b></td>
<td>"PEX"</td>
</tr>
<tr>
<td><b>Messages</b></td>
<td>
<ul>
<li>pexRequestMsg</li>
<li>pexResponseMsg</li>
</ul>
</td>
</tr>
</table>
<hr />
__multiplex__ *noun* a system or signal involving simultaneous transmission of
several messages along a single channel of communication.
## Resources
Each `MConnection` handles message transmission on multiple abstract communication
`Channel`s. Each channel has a globally unique byte id.
The byte id and the relative priorities of each `Channel` are configured upon
initialization of the connection.
* http://www.upnp-hacks.org/upnp.html
There are two methods for sending messages:
```go
func (m MConnection) Send(chId byte, msg interface{}) bool {}
func (m MConnection) TrySend(chId byte, msg interface{}) bool {}
```
`Send(chId, msg)` is a blocking call that waits until `msg` is successfully queued
for the channel with the given id byte `chId`. The message `msg` is serialized
using the `tendermint/binary` submodule's `WriteBinary()` reflection routine.
`TrySend(chId, msg)` is a nonblocking call that returns false if the channel's
queue is full.
`Send()` and `TrySend()` are also exposed for each `Peer`.
## Switch/Reactor
The `Switch` handles peer connections and exposes an API to receive incoming messages
on `Reactors`. Each `Reactor` is responsible for handling incoming messages of one
or more `Channels`. So while sending outgoing messages is typically performed on the peer,
incoming messages are received on the reactor.
```go
// Declare a MyReactor reactor that handles messages on MyChannelId.
type MyReactor struct{}
func (reactor MyReactor) GetChannels() []*ChannelDescriptor {
return []*ChannelDescriptor{ChannelDescriptor{Id:MyChannelId, Priority: 1}}
}
func (reactor MyReactor) Receive(chId byte, peer *Peer, msgBytes []byte) {
r, n, err := bytes.NewBuffer(msgBytes), new(int64), new(error)
msgString := ReadString(r, n, err)
fmt.Println(msgString)
}
// Other Reactor methods omitted for brevity
...
switch := NewSwitch([]Reactor{MyReactor{}})
...
// Send a random message to all outbound connections
for _, peer := range switch.Peers().List() {
if peer.IsOutbound() {
peer.Send(MyChannelId, "Here's a random message")
}
}
```
### PexReactor/AddrBook
A `PEXReactor` reactor implementation is provided to automate peer discovery.
```go
book := p2p.NewAddrBook(config.AddrBookFile())
pexReactor := p2p.NewPEXReactor(book)
...
switch := NewSwitch([]Reactor{pexReactor, myReactor, ...})
```

View File

@ -34,8 +34,27 @@ type receiveCbFunc func(chId byte, msgBytes []byte)
type errorCbFunc func(interface{})
/*
A MConnection wraps a network connection and handles buffering and multiplexing.
<essages are sent with ".Send(channelId, msg)".
Each peer has one `MConnection` (multiplex connection) instance.
__multiplex__ *noun* a system or signal involving simultaneous transmission of
several messages along a single channel of communication.
Each `MConnection` handles message transmission on multiple abstract communication
`Channel`s. Each channel has a globally unique byte id.
The byte id and the relative priorities of each `Channel` are configured upon
initialization of the connection.
There are two methods for sending messages:
func (m MConnection) Send(chId byte, msg interface{}) bool {}
func (m MConnection) TrySend(chId byte, msg interface{}) bool {}
`Send(chId, msg)` is a blocking call that waits until `msg` is successfully queued
for the channel with the given id byte `chId`. The message `msg` is serialized
using the `tendermint/binary` submodule's `WriteBinary()` reflection routine.
`TrySend(chId, msg)` is a nonblocking call that returns false if the channel's
queue is full.
Inbound message bytes are handled with an onReceive callback function.
*/
type MConnection struct {

View File

@ -10,18 +10,13 @@ import (
"github.com/tendermint/tendermint/p2p/upnp"
)
/*
Listener is part of a Server.
*/
type Listener interface {
Connections() <-chan net.Conn
ExternalAddress() *NetAddress
Stop()
}
/*
DefaultListener is an implementation of Listener.
*/
// Implements Listener
type DefaultListener struct {
listener net.Listener
extAddr *NetAddress

View File

@ -11,8 +11,6 @@ import (
"time"
)
/* NetAddress */
type NetAddress struct {
IP net.IP
Port uint16

View File

@ -10,8 +10,6 @@ import (
. "github.com/tendermint/tendermint/common"
)
/* Peer */
type Peer struct {
outbound bool
mconn *MConnection

View File

@ -4,9 +4,7 @@ import (
"sync"
)
/*
IPeerSet has a (immutable) subset of the methods of PeerSet.
*/
// IPeerSet has a (immutable) subset of the methods of PeerSet.
type IPeerSet interface {
Has(key string) bool
List() []*Peer
@ -15,10 +13,8 @@ type IPeerSet interface {
//-----------------------------------------------------------------------------
/*
PeerSet is a special structure for keeping a table of peers.
Iteration over the peers is super fast and thread-safe.
*/
// PeerSet is a special structure for keeping a table of peers.
// Iteration over the peers is super fast and thread-safe.
type PeerSet struct {
mtx sync.Mutex
lookup map[string]*peerSetItem

View File

@ -22,19 +22,10 @@ type Reactor interface {
//-----------------------------------------------------------------------------
/*
All communication amongst peers are multiplexed by "channels".
(Not the same as Go "channels")
To send a message, serialize it into a ByteSlice and send it to each peer.
For best performance, re-use the same immutable ByteSlice to each peer.
You can also use a TypedBytes{} struct for convenience.
You can find all connected and active peers by iterating over ".Peers().List()".
".Broadcast()" is provided for convenience, but by iterating over
the peers manually the caller can decide which subset receives a message.
Inbound messages are received by calling ".Receive()".
The receiver is responsible for decoding the message bytes, which may be preceded
by a single type byte if a TypedBytes{} was used.
The `Switch` handles peer connections and exposes an API to receive incoming messages
on `Reactors`. Each `Reactor` is responsible for handling incoming messages of one
or more `Channels`. So while sending outgoing messages is typically performed on the peer,
incoming messages are received on the reactor.
*/
type Switch struct {
reactors []Reactor

5
p2p/upnp/README.md Normal file
View File

@ -0,0 +1,5 @@
# `tendermint/p2p/upnp`
## Resources
* http://www.upnp-hacks.org/upnp.html