V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
rkonfj
V2EX  ›  Go 编程语言

现在搞 p2p 很简单了

  •  
  •   rkonfj · 2 天前 via iPhone · 3537 次点击

    我是 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)
    }
    
    13 条回复    2025-03-17 19:41:39 +08:00
    lekai63
        1
    lekai63  
       2 天前
    感谢。但似乎一下没想到很赞的使用场景。。
    lizhenda
        2
    lizhenda  
       2 天前
    什么场景适用呢? 做个相关的 demo 是不是更好点。
    lloovve
        3
    lloovve  
       2 天前 via iPhone
    Ipv6 下,两个 5g 或者 4g 手机能直连么
    kk2syc
        4
    kk2syc  
       2 天前   ❤️ 2
    我只能想到用你的 pg 复刻一个 qvod ,当年欠快播一个会员
    wangtian2020
        5
    wangtian2020  
       1 天前
    webrtc p2p 已经很成熟了,为什么其他语言不 all in 呢
    iYume
        6
    iYume  
       1 天前
    之前搞区块链时 libp2p 和 devp2p 都用过,你的介绍说的 nat / 25519 这些其他库也都有,我并不算特别了解,只是觉得在 README 搞个 vs. 块对比一下特性可能会便于大家直观看出来
    zzhirong
        7
    zzhirong  
       1 天前
    1. 看到 PG 第一反应联想到 PostgreSQL 。
    2. 在阅读 README 时,我发现了一个有趣的词——“Birthday Paradox (生日悖论,在一个群体中,只需要 23 个人,就有超过 50% 的概率存在两个人的生日相同)”,用在 NAT 穿越上,指的是在双方都知道对方 NAT 地址但不知道对方 NAT 映射端口的情况下,各自随机选择一组目标端口发起通信,从而有一定概率能建立连接,这不禁让人联想到你我相识全靠缘分。最近刚好看了两个关于概率相关的数据结构:跳跃表和 HyperLogLog 。感叹数学真美和烧脑。
    lujiaxing
        8
    lujiaxing  
       1 天前
    国内大概没啥用. 国内封得厉害. 连 WebRTC 都连不上更何况你这
    cloverzrg2
        9
    cloverzrg2  
       1 天前
    @zzhirong #7 同,我也是想到 postgresql ,不知道作者这个 pg 是什么的缩写呢
    zzhirong
        10
    zzhirong  
       1 天前
    @cloverzrg2 PeerGuard “夜幕降临,我的守望始于此,直至死亡将我收走。我不娶妻、不育子、不占有土地;我不争荣誉,不戴王冠;我只在城墙上生、老、病、死。我是黑暗中的剑,是守护 peer 的盾,我以我的生命和荣誉守护
    peers ,直到永远。”
    vfs
        11
    vfs  
       1 天前
    最关心这个 “NAT traversal with high success rate” 国内成功率有多少?
    sdvfO3n7a6RP18nN
        12
    sdvfO3n7a6RP18nN  
       1 天前 via iPhone
    这个可以搞 ipc 串流的,请问成功率有测试报告么
    stormtrooperx5
        13
    stormtrooperx5  
       1 天前
    跟 libp2p 有啥区别呢
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   993 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 21:54 · PVG 05:54 · LAX 14:54 · JFK 17:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.