github.com/kaiya/goutils@v1.0.1-0.20230226104005-4ae4a4dc3688/p2p/peers/main.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"net"
     7  	"os"
     8  	"strconv"
     9  	"strings"
    10  	"time"
    11  )
    12  
    13  var tag string
    14  
    15  const HAND_SHAKE_MSG = "我是打洞消息"
    16  
    17  func main() {
    18  	// 当前进程标记字符串,便于显示
    19  	tag = os.Args[1]
    20  	srcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 9983} // 注意端口必须固定
    21  	dstAddr := &net.UDPAddr{IP: net.ParseIP("34.96.219.198"), Port: 9981}
    22  	conn, err := net.DialUDP("udp", srcAddr, dstAddr)
    23  	if err != nil {
    24  		fmt.Println(err)
    25  	}
    26  	if _, err = conn.Write([]byte("hello, I'm new peer:" + tag)); err != nil {
    27  		log.Panic(err)
    28  	}
    29  	data := make([]byte, 1024)
    30  	n, remoteAddr, err := conn.ReadFromUDP(data)
    31  	if err != nil {
    32  		fmt.Printf("error during read: %s", err)
    33  	}
    34  	conn.Close()
    35  	anotherPeer := parseAddr(string(data[:n]))
    36  	fmt.Printf("local:%s server:%s another:%s\n", srcAddr, remoteAddr, anotherPeer.String())
    37  
    38  	// 开始打洞
    39  	bidirectionHole(srcAddr, &anotherPeer)
    40  
    41  }
    42  
    43  func parseAddr(addr string) net.UDPAddr {
    44  	t := strings.Split(addr, ":")
    45  	port, _ := strconv.Atoi(t[1])
    46  	return net.UDPAddr{
    47  		IP:   net.ParseIP(t[0]),
    48  		Port: port,
    49  	}
    50  }
    51  
    52  func bidirectionHole(srcAddr *net.UDPAddr, anotherAddr *net.UDPAddr) {
    53  	conn, err := net.DialUDP("udp", srcAddr, anotherAddr)
    54  	if err != nil {
    55  		fmt.Println(err)
    56  	}
    57  	defer conn.Close()
    58  	// 向另一个peer发送一条udp消息(对方peer的nat设备会丢弃该消息,非法来源),用意是在自身的nat设备打开一条可进入的通道,这样对方peer就可以发过来udp消息
    59  	if _, err = conn.Write([]byte(HAND_SHAKE_MSG)); err != nil {
    60  		log.Println("send handshake:", err)
    61  	}
    62  	go func() {
    63  		for {
    64  			time.Sleep(10 * time.Second)
    65  			if _, err = conn.Write([]byte("from [" + tag + "]")); err != nil {
    66  				log.Println("send msg fail", err)
    67  			}
    68  		}
    69  	}()
    70  	for {
    71  		data := make([]byte, 1024)
    72  		n, _, err := conn.ReadFromUDP(data)
    73  		if err != nil {
    74  			log.Printf("error during read: %s\n", err)
    75  		} else {
    76  			log.Printf("收到数据:%s\n", data[:n])
    77  		}
    78  	}
    79  }