说明
本人是刚学 libp2p, 这些博客 不能当作是教程或者是引导
。
也许会有大量错误,欢迎大佬指导。
此博客源码 imjoel/go-libp2p-learn
搭建一个简单的穿透服务
搭建穿透服务一共需要3步,
- 生成一个节点ID
- 创建一个 Host
- 等待连接
1. 生成节点ID 不用多说,github.com/libp2p/go-libp2p-examples 上有示例, 下面是我将目标代码整合成了一个方法
import (
crand "crypto/rand"
"github.com/libp2p/go-libp2p-core/crypto"
"io"
mrand "math/rand"
)
func generateIdentity(seed int64) (identity crypto.PrivKey, err error) {
var r io.Reader
if seed == 0 {
r = crand.Reader
} else {
r = mrand.New(mrand.NewSource(seed))
}
identity, _, err = crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, r)
return identity, err
}
2. 要创建一个 Host 很简单,如果要创建一个 relay host
只需要指定 OptActive
和 OptHop
选项即可. 下面是我抽出来的创建 relay host
的函数
import (
"context"
"fmt"
"github.com/libp2p/go-libp2p"
circuit "github.com/libp2p/go-libp2p-circuit"
"github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/host"
"log"
)
func makeRelayHost(port int, hostAddress string,
identity crypto.PrivKey, insecure bool) (host.Host, error) {
opts := []libp2p.Option{
libp2p.ListenAddrStrings(fmt.Sprintf("/ip4/%s/tcp/%d", hostAddress, port)),
libp2p.Identity(identity),
libp2p.EnableRelay(circuit.OptActive, circuit.OptHop),
}
if insecure {
opts = append(opts, libp2p.NoSecurity)
log.Println("[WARN] Insecure relay")
}
return libp2p.New(context.Background(), opts...)
}
3. 等待连接
创建一个简单的 relay server 可以参考 gitee.com/imjoel/go-libp2p-learn 中的示例代码
简单的聊天客户端
聊天客户端与穿透连接伪代码如下:
// 穿透服务的地址
var relayAddress string
// 同样连接到穿透服务的,朋友的节点ID
var targetPeerID string
// 创建一个 host
var myHost = new(host.Host)
// 连接到穿透服务
connectRelay(myHost, relayAddress)
if targetPeerID != "" {
// 主动连接朋友
connectFriend(myHost, targetPeerID)
} else {
// 等待朋友连接我
myHost.SetStreamHandler("/chat", func(){})
}
1. 创建 host
唯一需要注意的是该host 不能配置为 DisableRelay()
, 至少需要 OptDiscovery
选项
import (
"context"
"github.com/libp2p/go-libp2p"
circuit "github.com/libp2p/go-libp2p-circuit"
"github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/host"
"log"
)
func makeHost(identity crypto.PrivKey, insecure bool) (host.Host, error) {
opts := []libp2p.Option{
libp2p.ListenAddrStrings("/ip4/127.0.0.1/tcp/0"),
libp2p.Identity(identity),
libp2p.EnableRelay(circuit.OptDiscovery),
}
if insecure {
opts = append(opts, libp2p.NoSecurity)
log.Println("[WARN] Insecure relay")
}
return libp2p.New(context.Background(), opts...)
}
2. 连接 relay
import (
"context"
"fmt"
"github.com/libp2p/go-libp2p-core/host"
"github.com/libp2p/go-libp2p-core/peer"
ma "github.com/multiformats/go-multiaddr"
)
func connectRelay(h host.Host, relay string) error {
relayAddr, err := ma.NewMultiaddr(relay)
if err != nil {
return err
}
pid, err := relayAddr.ValueForProtocol(ma.P_P2P)
if err != nil {
return err
}
relayPeerID, err := peer.IDB58Decode(pid)
if err != nil {
return err
}
relayPeerAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/p2p/%s", pid))
relayAddress := relayAddr.Decapsulate(relayPeerAddr)
peerInfo := peer.AddrInfo{
ID: relayPeerID,
Addrs: []ma.Multiaddr{relayAddress},
}
return h.Connect(context.Background(), peerInfo)
}