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

现在搞 p2p 很简单了

  •  
  •   rkonfj · 16 小时 20 分钟前 via iPhone · 2458 次点击

    我是 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)
    }
    
    6 条回复    2025-03-17 11:37:29 +08:00
    lekai63
        1
    lekai63  
       15 小时 23 分钟前
    感谢。但似乎一下没想到很赞的使用场景。。
    lizhenda
        2
    lizhenda  
       15 小时 21 分钟前
    什么场景适用呢? 做个相关的 demo 是不是更好点。
    lloovve
        3
    lloovve  
       13 小时 56 分钟前 via iPhone
    Ipv6 下,两个 5g 或者 4g 手机能直连么
    kk2syc
        4
    kk2syc  
       11 小时 5 分钟前   ❤️ 2
    我只能想到用你的 pg 复刻一个 qvod ,当年欠快播一个会员
    wangtian2020
        5
    wangtian2020  
       3 小时 10 分钟前
    webrtc p2p 已经很成熟了,为什么其他语言不 all in 呢
    iYume
        6
    iYume  
       1 小时 53 分钟前
    之前搞区块链时 libp2p 和 devp2p 都用过,你的介绍说的 nat / 25519 这些其他库也都有,我并不算特别了解,只是觉得在 README 搞个 vs. 块对比一下特性可能会便于大家直观看出来
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4078 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 05:30 · PVG 13:30 · LAX 22:30 · JFK 01:30
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.