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 }