I just want to know how to create a node like the global bootstrap.
I am having some trouble when using libp2p, I would like to ask for your help.
I have 3 servers A, B, C.
Server A has a public IP address
Server B is a server behind the NAT network, no public IP address.
Server C is a server behind another NAT network, and no public IP.
I want server A as a global bootstrap node.
Servers B and C are connected to server A when they are run.
Server B and C are successfully connected to A.
I am having some trouble now, and B and C failed to communicate by creating a stream.
The following is A code as bootstrap,
A.go
//--------- strat of A.go---------
package main
import (
"context"
"flag"
"fmt"
"io/ioutil"
"os"
"os/signal"
"syscall"
"time"
dht "github.com/libp2p/go-libp2p-kad-dht"
"github.com/libp2p/go-libp2p"
circuit "github.com/libp2p/go-libp2p-circuit"
net "github.com/libp2p/go-libp2p-net"
ma "github.com/multiformats/go-multiaddr"
)
const defaultListenAddr = "/ip4/0.0.0.0/tcp/%d"
const protocl = "/chat/1.0.0"
func main() {
var port int
flag.IntVar(&port, "port", 30000, "listen port")
flag.Parse()
listenAddr := fmt.Sprintf(defaultListenAddr, port)
listen, err := ma.NewMultiaddr(listenAddr)
if err != nil {
fmt.Println(err)
return
}
opts := []libp2p.Option{
libp2p.ListenAddrs(listen),
libp2p.NATPortMap(),
libp2p.EnableRelay(circuit.OptHop),
}
ctx := context.Background()
host, err := libp2p.New(ctx, opts...)
if err != nil {
fmt.Println(err)
return
}
kademliaDHT, err := dht.New(ctx, host)
if err != nil {
fmt.Println(err)
return
}
if err = kademliaDHT.BootstrapWithConfig(ctx, dht.BootstrapConfig{1, 10 * time.Second, 10 * time.Second}); err != nil {
fmt.Println(err)
return
}
fmt.Printf("current node addr: %s/p2p/%s\n", listenAddr, host.ID().Pretty())
host.SetStreamHandler(protocl, handleStream)
for {
if kademliaDHT.RoutingTable().Size() > 0 {
rt := kademliaDHT.RoutingTable()
rt.Print()
}
time.Sleep(10 * time.Second)
}
quit := make(chan os.Signal)
signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
<-quit
}
func handleStream(s net.Stream) {
fmt.Printf("get stream from %s via %s\n", s.Conn().RemotePeer().Pretty(), s.Conn().RemoteMultiaddr().String())
data, err := ioutil.ReadAll(s)
if err != nil {
fmt.Println(err)
return
}
if len(data) > 0 {
fmt.Printf("Message from %s:%s\n", s.Conn().RemotePeer().Pretty(), string(data))
}
defer s.Close()
}
//--------end of A.go--------
B and C use the same code
B.go
//--------- strat of B.go---------
package main
import (
"bufio"
"context"
"flag"
"fmt"
"io/ioutil"
"os"
"os/signal"
"syscall"
"time"
dht "github.com/libp2p/go-libp2p-kad-dht"
"github.com/libp2p/go-libp2p"
circuit "github.com/libp2p/go-libp2p-circuit"
"github.com/libp2p/go-libp2p-core/host"
"github.com/libp2p/go-libp2p-core/peer"
net "github.com/libp2p/go-libp2p-net"
"github.com/multiformats/go-multiaddr"
ma "github.com/multiformats/go-multiaddr"
)
const defaultListenAddr = "/ip4/0.0.0.0/tcp/%d"
const protocl = "/chat/1.0.0"
func main() {
var bs string
var port int
flag.StringVar(&bs, "bs", "", "bs addr")
flag.IntVar(&port, "port", 30000, "listen port")
flag.Parse()
listenAddr := fmt.Sprintf(defaultListenAddr, port)
listen, err := ma.NewMultiaddr(listenAddr)
if err != nil {
fmt.Println(err)
return
}
opts := []libp2p.Option{
libp2p.ListenAddrs(listen),
libp2p.NATPortMap(),
libp2p.EnableRelay(circuit.OptHop),
}
ctx := context.Background()
ho, err := libp2p.New(ctx, opts...)
if err != nil {
fmt.Println(err)
return
}
kademliaDHT, err := dht.New(ctx, ho)
if err != nil {
fmt.Println(err)
return
}
if err = kademliaDHT.Bootstrap(ctx); err != nil {
fmt.Println(err)
return
}
fmt.Printf("current node addr: %s/p2p/%s\n", listenAddr, ho.ID().Pretty())
if bs != "" {
bsAddr, err := multiaddr.NewMultiaddr(bs)
if err != nil {
fmt.Println(err)
return
}
bsInfo, err := peer.AddrInfoFromP2pAddr(bsAddr)
if err != nil {
fmt.Println(err)
return
}
ho.Connect(ctx, *bsInfo)
}
ho.SetStreamHandler(protocl, handleStream)
/*go func(kdht *dht.IpfsDHT) {
for {
if kdht.RoutingTable().Size() > 0 {
rt := kdht.RoutingTable()
rt.Print()
}
time.Sleep(10 * time.Second)
}
}(kademliaDHT)*/
for {
for _, pid := range ho.Peerstore().Peers() {
fmt.Printf("本地存储的节点 peer: %v\n", pid.Pretty())
genStream(ho, pid)
}
fmt.Println("-----------")
time.Sleep(3 * time.Second)
}
quit := make(chan os.Signal)
signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
<-quit
}
func genStream(h host.Host, pid peer.ID) {
if h.ID() == pid {
return
}
s, err := h.NewStream(context.Background(), pid, protocl)
fmt.Println("create stream,", s, err)
if err != nil {
fmt.Println(err)
return
}
w := bufio.NewWriter(s)
msg := "HI\n"
msg = fmt.Sprintf("%v %s", time.Now(), msg)
num, err := w.WriteString(msg)
if num != len(msg) {
fmt.Printf("expected to write %d bytes, wrote %d", len(msg), num)
return
}
if err != nil {
fmt.Println(err)
return
}
if err = w.Flush(); err != nil {
fmt.Println(err)
return
}
s.Close()
//return nil
time.Sleep(3 * time.Second)
}
func handleStream(s net.Stream) {
fmt.Printf("get stream from %s via %s\n", s.Conn().RemotePeer().Pretty(), s.Conn().RemoteMultiaddr().String())
data, err := ioutil.ReadAll(s)
if err != nil {
fmt.Println(err)
return
}
if len(data) > 0 {
fmt.Printf("Message from %s:%s\n", s.Conn().RemotePeer().Pretty(), string(data))
}
defer s.Close()
}
//--------end of B.go--------