国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Derek解讀Bytom源碼-P2P網絡 upnp端口映射

ranwu / 930人閱讀

摘要:作者簡介地址地址本章介紹代碼網絡中端口映射作者使用操作系統,其他平臺也大同小異介紹通用即插即用。端口映射將一個外部端口映射到一個內網。

作者:Derek

簡介

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

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

本章介紹bytom代碼P2P網絡中upnp端口映射

作者使用MacOS操作系統,其他平臺也大同小異

Golang Version: 1.8

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
" +
            "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發送一條多播請求
        _, 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 := "
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
            }
            // 獲得設備的描述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 := "
" +
        "" + 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 := "
" +
        "" + 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 := "
" +
        ""

    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
}

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/24258.html

相關文章

  • Derek解讀Bytom源碼-P2P網絡 地址簿

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

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

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

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

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

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

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

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

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

    GitChat 評論0 收藏0

發表評論

0條評論

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