成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Derek解讀Bytom源碼-P2P網(wǎng)絡(luò) upnp端口映射

ranwu / 953人閱讀

摘要:作者簡介地址地址本章介紹代碼網(wǎng)絡(luò)中端口映射作者使用操作系統(tǒng),其他平臺也大同小異介紹通用即插即用。端口映射將一個外部端口映射到一個內(nèi)網(wǎng)。

作者:Derek

簡介

Github地址:https://github.com/Bytom/bytom

Gitee地址:https://gitee.com/BytomBlockc...

本章介紹bytom代碼P2P網(wǎng)絡(luò)中upnp端口映射

作者使用MacOS操作系統(tǒng),其他平臺也大同小異

Golang Version: 1.8

UPNP介紹

UPNP(Universal Plug and Play)通用即插即用。UPNP端口映射將一個外部端口映射到一個內(nèi)網(wǎng)ip:port。從而實現(xiàn)p2p網(wǎng)絡(luò)從外網(wǎng)能夠穿透網(wǎng)關(guān)訪問到內(nèi)網(wǎng)的bytomd節(jié)點。

UPNP協(xié)議

SSDP(Simple Service Discovery Protocol 簡單服務(wù)發(fā)現(xiàn)協(xié)議)
GENA(Generic Event Notification Architecture 通用事件通知結(jié)構(gòu))
SOAP(Simple Object Access Protocol 簡單對象訪問協(xié)議)
XML(Extensible Markup Language 可擴張標(biāo)記語言)

UPNP代碼

p2p/upnp/upnp.go

發(fā)現(xiàn)網(wǎng)絡(luò)中支持UPNP功能的設(shè)備

從網(wǎng)絡(luò)中發(fā)現(xiàn)支持UPNP功能的設(shè)備,并得到該設(shè)備的location和url等相關(guān)信息

type upnpNAT struct {
    serviceURL string // 設(shè)備的描述文件URL,用于得到該設(shè)備的描述信息
    ourIP      string // 節(jié)點本地ip地址
    urnDomain  string // 設(shè)備類型
}

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協(xié)議定義的發(fā)現(xiàn)請求。
    buf := bytes.NewBufferString(
        "M-SEARCH * HTTP/1.1
" +
            "HOST: 239.255.255.250:1900
" +
            "ST: ssdp:all
" +
            "MAN: "ssdp:discover"
" +
            "MX: 2

")
    message := buf.Bytes()
    answerBytes := make([]byte, 1024)
    for i := 0; i < 3; i++ {
        // 向239.255.255.250:1900發(fā)送一條多播請求
        _, err = socket.WriteToUDP(message, ssdp)
        if err != nil {
            return
        }
        // 如果從網(wǎng)絡(luò)中發(fā)現(xiàn)UPNP設(shè)備則會從239.255.255.250:1900收到響應(yīng)消息
        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
            // 獲得設(shè)備location
            locString := "
location:"
            answer = strings.ToLower(answer)
            locIndex := strings.Index(answer, locString)
            if locIndex < 0 {
                continue
            }
            loc := answer[locIndex+len(locString):]
            endIndex := strings.Index(loc, "
")
            if endIndex < 0 {
                continue
            }
            // 獲得設(shè)備的描述url和設(shè)備類型
            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設(shè)備發(fā)送一條http post請求,將內(nèi)部網(wǎng)絡(luò)ip:port和外部網(wǎng)絡(luò)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 := "
" +
        "" + 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設(shè)備發(fā)送一條http post請求,將內(nèi)部網(wǎng)絡(luò)ip:port和外部網(wǎng)絡(luò)ip:port刪除映射關(guān)系

func (n *upnpNAT) DeletePortMapping(protocol string, externalPort, internalPort int) (err error) {

    message := "
" +
        "" + 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
}
獲取映射后的公網(wǎng)地址
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 := "
" +
        ""

    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
}

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/24258.html

相關(guān)文章

  • Derek解讀Bytom源碼-P2P網(wǎng)絡(luò) 地址簿

    摘要:作者簡介地址地址本章介紹代碼網(wǎng)絡(luò)中地址簿作者使用操作系統(tǒng),其他平臺也大同小異介紹用于存儲網(wǎng)絡(luò)中保留最近的對端節(jié)點地址在下,默認(rèn)的地址簿路徑存儲在地址簿格式地址類型在中存儲的地址有兩種標(biāo)識新地址,不可靠地址未成功連接過。 作者:Derek 簡介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomB...

    Kahn 評論0 收藏0
  • Derek解讀Bytom源碼-啟動與停止

    摘要:只有當(dāng)觸發(fā)了或才能終止進程退出。退出時執(zhí)行如下操作會將挖礦功能停止,網(wǎng)絡(luò)停止等操作。 作者:Derek 簡介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockc... 本章介紹bytom代碼啟動、節(jié)點初始化、及停止的過程 作者使用MacOS操作系統(tǒng),其他平臺也大同小異Golang V...

    Godtoy 評論0 收藏0
  • Derek解讀Bytom源碼-Api Server接口服務(wù)

    摘要:首先讀取請求內(nèi)容,解析請求,接著匹配相應(yīng)的路由項,隨后調(diào)用路由項的回調(diào)函數(shù)來處理。每一個路由項由請求方法和回調(diào)函數(shù)組成將監(jiān)聽地址作為參數(shù),最終執(zhí)行開始服務(wù)于外部請求創(chuàng)建對象首先,實例化對象。我們可以看到一條項由和對應(yīng)的回調(diào)函數(shù)組成。 作者:Derek 簡介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com...

    GitCafe 評論0 收藏0
  • Derek解讀Bytom源碼-持久化存儲LevelDB

    摘要:函數(shù)總共操作有兩步從緩存中查詢值,如果查到則返回如果為從緩存中查詢到則回調(diào)回調(diào)函數(shù)?;卣{(diào)函數(shù)會將從磁盤上獲得到塊信息存儲到緩存中并返回該塊的信息?;卣{(diào)函數(shù)實際上調(diào)取的是下的,它會從磁盤中獲取信息并返回。 作者:Derek 簡介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockc......

    Eminjannn 評論0 收藏0
  • Derek解讀Bytom源碼分析-持久化存儲LevelDB

    摘要:函數(shù)總共操作有兩步從緩存中查詢值,如果查到則返回如果為從緩存中查詢到則回調(diào)回調(diào)函數(shù)。回調(diào)函數(shù)會將從磁盤上獲得到塊信息存儲到緩存中并返回該塊的信息。回調(diào)函數(shù)實際上調(diào)取的是下的,它會從磁盤中獲取信息并返回。 簡介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockc... 本章介紹Dere...

    GitChat 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<