现在搞 p2p 很简单了

2025 年 3 月 16 日
 rkonfj

我是 https://github.com/sigcn/pg 仓库的作者。 经过几个月的努力,现在用 PG 写 P2P 网络程序似乎很简单了。 发帖希望

  1. 得到一些关于 P2P 开发库 api 更好的设计思路。易用性和扩展性。
  2. 有感兴趣的朋友会基于 PG 开发一些实用的 P2P 应用。

这是一个访问虚拟网络内节点 HTTP 服务的示例

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/url"
	"os"
	"time"

	"github.com/sigcn/pg/disco"
	"github.com/sigcn/pg/langs"
	"github.com/sigcn/pg/p2p"
	"github.com/sigcn/pg/peermap/network"
	"github.com/sigcn/pg/vpn"
	"github.com/sigcn/pg/vpn/nic"
	"github.com/sigcn/pg/vpn/nic/gvisor"
	"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
	"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
	"gvisor.dev/gvisor/pkg/tcpip/stack"
	"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
)

var (
	server     = "wss://openpg.in/pg"
	secretFile = "psns.json"
	_, ip4, _  = net.ParseCIDR("100.99.0.27/24")
)

// prepareSecret 准备 JSONSecret 用于加入 PG 网络
func prepareSecret() error {
	fetchSecret := func() error {
		join, err := network.JoinOIDC("", server)
		if err != nil {
			return err
		}
		fmt.Println("Open the following link to authenticate")
		fmt.Println(join.AuthURL())
		ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
		secret, err := join.Wait(ctx)
		cancel()
		if err != nil {
			panic(err)
		}
		f, err := os.Create(secretFile)
		if err != nil {
			return err
		}
		json.NewEncoder(f).Encode(secret)
		return nil
	}

	f, err := os.Open(secretFile)
	if err != nil {
		return fetchSecret()
	}
	var secret disco.NetworkSecret
	if err := json.NewDecoder(f).Decode(&secret); err != nil {
		return err
	}
	if time.Now().After(secret.Expire) {
		return fetchSecret()
	}
	return nil
}

// startVPN 启动 VPN (gVisor + p2p)
func startVPN(ctx context.Context) *gvisor.GvisorCard {
	s := stack.New(stack.Options{
		NetworkProtocols:   []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},
		TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol},
	})

	vnic := nic.VirtualNIC{NIC: &gvisor.GvisorCard{Stack: s, Config: nic.Config{IPv4: ip4.String()}}}
	packetConn := langs.Must(p2p.ListenPacket(
		&disco.Server{Secret: &disco.FileSecretStore{StoreFilePath: secretFile}, URL: server},
		p2p.ListenPeerUp(func(pi disco.PeerID, v url.Values) {
			vnic.AddPeer(nic.Peer{Addr: pi, IPv4: v.Get("alias1"), IPv6: v.Get("alias2"), Meta: v})
		}),
		p2p.ListenPeerSecure(),
		p2p.PeerAlias1(ip4.IP.String()),
	))

	go vpn.New(vpn.Config{MTU: 1371}).Run(ctx, &vnic, packetConn)
	return vnic.NIC.(*gvisor.GvisorCard)
}

func main() {
	// 获取 JSONSecret
	if err := prepareSecret(); err != nil {
		panic(err)
	}

	// 启动 gVisor VPN
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	gvisorCard := startVPN(ctx)

	// HTTP 请求
	cli := http.Client{
		Transport: &http.Transport{DialContext: gvisorCard.DialContext},
		Timeout:   15 * time.Second,
	}

	r := langs.Must(cli.Get("http://100.99.0.2"))
	defer r.Body.Close()
	io.Copy(os.Stdout, r.Body)
}
5112 次点击
所在节点    Go 编程语言
14 条回复
lekai63
2025 年 3 月 16 日
感谢。但似乎一下没想到很赞的使用场景。。
lizhenda
2025 年 3 月 16 日
什么场景适用呢? 做个相关的 demo 是不是更好点。
lloovve
2025 年 3 月 16 日
Ipv6 下,两个 5g 或者 4g 手机能直连么
v1
2025 年 3 月 17 日
我只能想到用你的 pg 复刻一个 qvod ,当年欠快播一个会员
wangtian2020
2025 年 3 月 17 日
webrtc p2p 已经很成熟了,为什么其他语言不 all in 呢
iYume
2025 年 3 月 17 日
之前搞区块链时 libp2p 和 devp2p 都用过,你的介绍说的 nat / 25519 这些其他库也都有,我并不算特别了解,只是觉得在 README 搞个 vs. 块对比一下特性可能会便于大家直观看出来
zzhirong
2025 年 3 月 17 日
1. 看到 PG 第一反应联想到 PostgreSQL 。
2. 在阅读 README 时,我发现了一个有趣的词——“Birthday Paradox (生日悖论,在一个群体中,只需要 23 个人,就有超过 50% 的概率存在两个人的生日相同)”,用在 NAT 穿越上,指的是在双方都知道对方 NAT 地址但不知道对方 NAT 映射端口的情况下,各自随机选择一组目标端口发起通信,从而有一定概率能建立连接,这不禁让人联想到你我相识全靠缘分。最近刚好看了两个关于概率相关的数据结构:跳跃表和 HyperLogLog 。感叹数学真美和烧脑。
lujiaxing
2025 年 3 月 17 日
国内大概没啥用. 国内封得厉害. 连 WebRTC 都连不上更何况你这
cloverzrg2
2025 年 3 月 17 日
@zzhirong #7 同,我也是想到 postgresql ,不知道作者这个 pg 是什么的缩写呢
zzhirong
2025 年 3 月 17 日
@cloverzrg2 PeerGuard “夜幕降临,我的守望始于此,直至死亡将我收走。我不娶妻、不育子、不占有土地;我不争荣誉,不戴王冠;我只在城墙上生、老、病、死。我是黑暗中的剑,是守护 peer 的盾,我以我的生命和荣誉守护
peers ,直到永远。”
vfs
2025 年 3 月 17 日
最关心这个 “NAT traversal with high success rate” 国内成功率有多少?
sdvfO3n7a6RP18nN
2025 年 3 月 17 日
这个可以搞 ipc 串流的,请问成功率有测试报告么
stormtrooperx5
2025 年 3 月 17 日
跟 libp2p 有啥区别呢
flynaj
2025 年 3 月 20 日
@lloovve 看运营商的防火墙配置,更手机防火墙配置,云南电信,小米手机可以直连。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1118867

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX