Install go-libp2p
go get -u -d github.com/libp2p/go-libp2p/...
cd $GOPATH/src/github.com/libp2p/go-libp2p
make
make deps
官网给出了安装说明:
go get 中 -u 表示下载最新版的依赖,-d 表示只下载不安装,当然你需要先安装 golang 才能使用 go get ,这里推荐安装 1.10.x 版本
golang安装包 : https://studygolang.com/dl
make 时需要下载 gx 组件,如果想直接用 make 来下载最好还是先“科学上网”,如果直接在 github 上下载安装 gx 则无需担心 “科学上网问题”
make deps 是要下载全部依赖了,这里会用 gx 来完成下载,第一次用时你会发现他要到 ipfs.io 去 get 依赖包,但是即便“科学上网”了也还是无法访问,其实只要在本地先启动一个 ipfs 节点就可以了,他会优先在本地的 ipfs 节点获取资源
IPFS 的下载和安装 : https://ipfs.io/docs/install/
启动命令: ipfs daemon
然后再去 make deps 经过漫长的等待,即可完成依赖的安装
很多小伙伴是不是都在这一步放弃了 go-libp2p 呀?其实我也挺讨厌这个 gx 的,不如 govendor 用着舒服,不幸的是想继续探索 go-libp2p 你就必须要掌握 gx 的用法,并且要去习惯使用 gx
安装还是比较容易的,一定要粗略的看一遍说明书再去看代码和例子,否则很难发现它的美
libp2p 说明书: https://github.com/libp2p/specs
Example
PingService
使用 libp2p 做服务是我们学习的目的,通过 PingService 来入门是个不错的选择,简单看一下 PingService 的代码,你会发现实现一个服务非常简单, host.Host 接口是核心
PingService : http://github.com/libp2p/go-libp2p/p2p/protocol/ping/ping.go
......
const ID = "/ipfs/ping/1.0.0"
type PingService struct {
Host host.Host
}
func NewPingService(h host.Host) *PingService {
ps := &PingService{h}
h.SetStreamHandler(ID, ps.PingHandler)
return ps
}
func (p *PingService) PingHandler(s inet.Stream) {
......
}
func (ps *PingService) Ping(ctx context.Context, p peer.ID) (<-chan time.Duration, error) {
s, err := ps.Host.NewStream(ctx, p, ID)
......
}
......
这个代码片段演示如何通过 host.Host 接口构建一个服务,Host 接口描述如下:
Host is an object participating in a p2p network, which implements protocols or provides services. It handles requests like a Server, and issues requests like a Client. It is called Host because it is both Server and Client (and Peer may be confusing).
在文章的结尾贴出了 Host 接口的代码,这个服务主要使用下面这两个方法
SetStreamHandler(pid protocol.ID, handler inet.StreamHandler)
首先通过 Host.SetStreamHandler 来为 "/ipfs/ping/1.0.0" 协议指定 callback 方法,这里指定了 PingHandler 方法,参数中的 inet.Stream 接口对 io 接口做了扩展,这里要做的就是当请求到来时对 s 的输入流做读操作NewStream(ctx context.Context, p peer.ID, pids ...protocol.ID) (inet.Stream, error)
在 Ping 方法被调用时首先通过 NewStream 打开了一个流,在 p2p 网络中打开流都是有目标的,这个目标就是 peer.ID ,因为这个 peer 上可能会注册很多服务,所以也要指明服务ID,就是参数中的 protocol.ID ,剩下的工作就是向 s 的输出流中写入数据包了。
TODO : 调用 PingService
感觉上调用一个服务比编写一个服务复杂的多,
首先NewHost就是一个非常复杂的操作,参数中的 Network 接口我们用 Swarm 来填充,那么 swarm 又是什么呢?它在这里是 Network 接口的一个实现,
Host 接口有两个实现,我们用 BasicHost 来实例化 Host 接口.
BasicHost: (github.com/libp2p/go-libp2p/p2p/host/basic/basic_host.go)
第二个参数 net 是 Network 接口类型,我们用 swarm 对象来填充即可得到一个 Host 接口的实现对象
// NewHost constructs a new *BasicHost and activates it by attaching its stream and connection handlers to the given [inet.Network](http://inet.Network).
func NewHost(ctx context.Context, net inet.Network, opts *HostOpts) (*BasicHost, error) {
......
go-libp2p-host 接口
// Host is an object participating in a p2p network, which implements protocols or provides services. It handles requests like a Server, and issues requests like a Client. It is called Host because it is both Server and Client (and Peer may be confusing).
type Host interface {
// ID returns the (local) [peer.ID](http://peer.ID) associated with this Host
ID() peer.ID
// Peerstore returns the Host's repository of Peer Addresses and Keys.
Peerstore() pstore.Peerstore
// Returns the listen addresses of the Host
Addrs() []ma.Multiaddr
// Networks returns the Network interface of the Host
Network() inet.Network
// Mux returns the Mux multiplexing incoming streams to protocol handlers
Mux() *msmux.MultistreamMuxer
// Connect ensures there is a connection between this host and the peer with given [peer.ID](http://peer.ID). Connect will absorb the addresses in pi into its internal peerstore. If there is not an active connection, Connect will issue a h.Network.Dial, and block until a connection is open, or an error is returned.
// TODO: Relay + NAT.
Connect(ctx context.Context, pi pstore.PeerInfo) error
// SetStreamHandler sets the protocol handler on the Host's Mux.
// This is equivalent to:
// host.Mux().SetHandler(proto, handler)
// (Threadsafe)
SetStreamHandler(pid protocol.ID, handler inet.StreamHandler)
// SetStreamHandlerMatch sets the protocol handler on the Host's Mux
// using a matching function for protocol selection.
SetStreamHandlerMatch(protocol.ID, func(string) bool, inet.StreamHandler)
// RemoveStreamHandler removes a handler on the mux that was set by
// SetStreamHandler
RemoveStreamHandler(pid protocol.ID)
// NewStream opens a new stream to given peer p, and writes a p2p/protocol
// header with given [protocol.ID](http://protocol.ID). If there is no connection to p, attempts
// to create one. If ProtocolID is "", writes no header.
// (Threadsafe)
NewStream(ctx context.Context, p peer.ID, pids ...protocol.ID) (inet.Stream, error)
// Close shuts down the host, its Network, and services.
Close() error
// ConnManager returns this hosts connection manager
ConnManager() ifconnmgr.ConnManager
}
go-libp2p-net 中的 Network 接口
// Network is the interface used to connect to the outside world. It dials and listens for connections. it uses a Swarm to pool connnections (see swarm pkg, and peerstream.Swarm). Connections are encrypted with a TLS-like protocol.
type Network interface {
Dialer
io.Closer
// SetStreamHandler sets the handler for new streams opened by the remote side. This operation is threadsafe.
SetStreamHandler(StreamHandler)
// SetConnHandler sets the handler for new connections opened by the remote side. This operation is threadsafe.
SetConnHandler(ConnHandler)
// NewStream returns a new stream to given peer p. If there is no connection to p, attempts to create one.
NewStream(context.Context, peer.ID) (Stream, error)
// Listen tells the network to start listening on given multiaddrs.
Listen(...ma.Multiaddr) error
// ListenAddresses returns a list of addresses at which this network listens.
ListenAddresses() []ma.Multiaddr
// InterfaceListenAddresses returns a list of addresses at which this network listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to use the known local interfaces.
InterfaceListenAddresses() ([]ma.Multiaddr, error)
// Process returns the network's Process
Process() goprocess.Process
}
有疑问加站长微信联系(非本文作者)