千家信息网

Bytom怎么实现P2P网络upnp端口映射

发表于:2025-12-02 作者:千家信息网编辑
千家信息网最后更新 2025年12月02日,这篇文章主要介绍"Bytom怎么实现P2P网络upnp端口映射",在日常操作中,相信很多人在Bytom怎么实现P2P网络upnp端口映射问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希
千家信息网最后更新 2025年12月02日Bytom怎么实现P2P网络upnp端口映射

这篇文章主要介绍"Bytom怎么实现P2P网络upnp端口映射",在日常操作中,相信很多人在Bytom怎么实现P2P网络upnp端口映射问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"Bytom怎么实现P2P网络upnp端口映射"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

UPNP介绍

UPNP(Universal Plug and Play)通用即插即用。UPNP端口映射将一个外部端口映射到一个内网ip:port。从而实现p2p网络从外网能够穿透网关访问到内网的bytomd节点。

UPNP协议

SSDP(Simple Service Discovery Protocol 简单服务发现协议) GENA(Generic Event Notification Architecture 通用事件通知结构) SOAP(Simple Object Access Protocol 简单对象访问协议) XML(Extensible Markup Language 可扩张标记语言)

UPNP代码

** p2p/upnp/upnp.go **

发现网络中支持UPNP功能的设备

从网络中发现支持UPNP功能的设备,并得到该设备的location和url等相关信息

type upnpNAT struct {        serviceURL string // 设备的描述文件URL,用于得到该设备的描述信息        ourIP      string // 节点本地ip地址        urnDomain  string // 设备类型}func Discover() (nat NAT, err error) {        ssdp, err := net.ResolveUDPAddr("udp4", "239.255.255.250:1900")        if err != nil {                return        }        conn, err := net.ListenPacket("udp4", ":0")        if err != nil {                return        }        socket := conn.(*net.UDPConn)        defer socket.Close()        err = socket.SetDeadline(time.Now().Add(3 * time.Second))        if err != nil {                return        }        st := "InternetGatewayDevice:1"        // 多播请求:M-SEARCH SSDP协议定义的发现请求。        buf := bytes.NewBufferString(                "M-SEARCH * HTTP/1.1\r\n" +                        "HOST: 239.255.255.250:1900\r\n" +                        "ST: ssdp:all\r\n" +                        "MAN: \"ssdp:discover\"\r\n" +                        "MX: 2\r\n\r\n")        message := buf.Bytes()        answerBytes := make([]byte, 1024)        for i := 0; i < 3; i++ {                // 向239.255.255.250:1900发送一条多播请求                _, err = socket.WriteToUDP(message, ssdp)                if err != nil {                        return                }                // 如果从网络中发现UPNP设备则会从239.255.255.250:1900收到响应消息                var n int                n, _, err = socket.ReadFromUDP(answerBytes)                for {                        n, _, err = socket.ReadFromUDP(answerBytes)                        if err != nil {                                break                        }                        answer := string(answerBytes[0:n])                        if strings.Index(answer, st) < 0 {                                continue                        }                        // HTTP header field names are case-insensitive.                        // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2                        // 获得设备location                        locString := "\r\nlocation:"                        answer = strings.ToLower(answer)                        locIndex := strings.Index(answer, locString)                        if locIndex < 0 {                                continue                        }                        loc := answer[locIndex+len(locString):]                        endIndex := strings.Index(loc, "\r\n")                        if endIndex < 0 {                                continue                        }                        // 获得设备的描述url和设备类型                        locURL := strings.TrimSpace(loc[0:endIndex])                        var serviceURL, urnDomain string                        serviceURL, urnDomain, err = getServiceURL(locURL)                        if err != nil {                                return                        }                        var ourIP net.IP                        ourIP, err = localIPv4()                        if err != nil {                                return                        }                        nat = &upnpNAT{serviceURL: serviceURL, ourIP: ourIP.String(), urnDomain: urnDomain}                        return                }        }        err = errors.New("UPnP port discovery failed.")        return}

添加端口映射

向upnp设备发送一条http post请求,将内部网络ip:port和外部网络ip:port做映射

func (n *upnpNAT) AddPortMapping(protocol string, externalPort, internalPort int, description string, timeout int) (mappedExternalPort int, err error) {        // A single concatenation would break ARM compilation.        message := "\r\n" +                "" + strconv.Itoa(externalPort)        message += "" + protocol + ""        message += "" + strconv.Itoa(internalPort) + "" +                "" + n.ourIP + "" +                "1"        message += description +                "" + strconv.Itoa(timeout) +                ""        var response *http.Response        response, err = soapRequest(n.serviceURL, "AddPortMapping", message, n.urnDomain)        if response != nil {                defer response.Body.Close()        }        if err != nil {                return        }        // TODO: check response to see if the port was forwarded        // log.Println(message, response)        // JAE:        // body, err := ioutil.ReadAll(response.Body)        // fmt.Println(string(body), err)        mappedExternalPort = externalPort        _ = response        return}

删除端口映射

向upnp设备发送一条http post请求,将内部网络ip:port和外部网络ip:port删除映射关系

func (n *upnpNAT) DeletePortMapping(protocol string, externalPort, internalPort int) (err error) {        message := "\r\n" +                "" + strconv.Itoa(externalPort) +                "" + protocol + "" +                ""        var response *http.Response        response, err = soapRequest(n.serviceURL, "DeletePortMapping", message, n.urnDomain)        if response != nil {                defer response.Body.Close()        }        if err != nil {                return        }        // TODO: check response to see if the port was deleted        // log.Println(message, response)        _ = response        return}

获取映射后的公网地址

func (n *upnpNAT) GetExternalAddress() (addr net.IP, err error) {        info, err := n.getExternalIPAddress()        if err != nil {                return        }        addr = net.ParseIP(info.externalIpAddress)        return}func (n *upnpNAT) getExternalIPAddress() (info statusInfo, err error) {        message := "\r\n" +                ""        var response *http.Response        response, err = soapRequest(n.serviceURL, "GetExternalIPAddress", message, n.urnDomain)        if response != nil {                defer response.Body.Close()        }        if err != nil {                return        }        var envelope Envelope        data, err := ioutil.ReadAll(response.Body)        reader := bytes.NewReader(data)        xml.NewDecoder(reader).Decode(&envelope)        info = statusInfo{envelope.Soap.ExternalIP.IPAddress}        if err != nil {                return        }        return}

到此,关于"Bytom怎么实现P2P网络upnp端口映射"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

0