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

資訊專欄INFORMATION COLUMN

剝開比原看代碼03:比原是如何監(jiān)聽p2p端口的

layman / 1366人閱讀

摘要:啟動直到進(jìn)入所以我們首先需要知道,比原在源代碼中是如何啟動,并且一步步走進(jìn)了的世界。后面省略了一些代碼,主要是用來獲取當(dāng)前監(jiān)聽的實(shí)際以及外網(wǎng),并記錄在日志中。

比原是如何監(jiān)聽p2p端口的

我們知道,在使用bytomd init --chain_id mainnet/testnet/solonet初始化比原的時(shí)候,它會根據(jù)給定的chain_id的不同,使用不同的端口(參看config/toml.go#L29):

mainnet(連接到主網(wǎng)): 46657

testnet(連接到測試網(wǎng)): 46656

solonet(本地多帶帶節(jié)點(diǎn)): 46658

對于我來說,由于只需要對本地運(yùn)行的一個(gè)比原節(jié)點(diǎn)進(jìn)行分析,所以可以采用第3個(gè)chain_id,即solonet。這樣它啟動之后,不會與其它的節(jié)點(diǎn)主動連接,可以減少其它節(jié)點(diǎn)對于我們的干擾。

所以在啟動的時(shí)候,我的命令是這樣的:

cd cmd/bytomd
./bytomd init --chain_id solonet
./bytomd node

它就會監(jiān)聽46658端口,等待其它節(jié)點(diǎn)的連接。

連上看看

如果這時(shí)我們使用telnet來連接其46658端口,成功連接上之后,可以看到它會發(fā)給我們一些亂碼,大概如下:

$ telnet localhost 46658
Trying 127.0.0.1...
Connected to localhost.
Escape character is "^]".
??S??%?z???_?端??????U[e

我們也許會好奇,它發(fā)給我們的到底是什么?

但是這個(gè)問題留待下次回答,因?yàn)槭紫龋仍?jié)點(diǎn)必須能夠監(jiān)聽這個(gè)端口,我們才能連上。所以這次我們的問題是:

比原在代碼中是如何監(jiān)聽這個(gè)端口的? 端口已經(jīng)寫在config.toml

在前面,當(dāng)我們使用./bytomd init --chain_id solonet初始化比原以后,比原會在本地的數(shù)據(jù)目錄中生成一個(gè)config.toml的配置文件,內(nèi)容大約如下:

# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml
fast_sync = true
db_backend = "leveldb"
api_addr = "0.0.0.0:9888"
chain_id = "solonet"
[p2p]
laddr = "tcp://0.0.0.0:46658"
seeds = ""

其中[p2p]下面的laddr,就是該節(jié)點(diǎn)監(jiān)聽的地址和端口。

對于laddr = "tcp://0.0.0.0:46658",它是意思是:

使用的是tcp協(xié)議

監(jiān)聽的ip是0.0.0.0,是指監(jiān)聽本機(jī)所有ip地址。這樣該節(jié)點(diǎn)既允許本地訪問,也允許外部主機(jī)訪問。如果你只想讓它監(jiān)聽某一個(gè)ip,手動修改該配置文件即可

46658,就是我們在這個(gè)問題中關(guān)注的端口了,它與該節(jié)點(diǎn)與其它節(jié)點(diǎn)交互數(shù)據(jù)使用的端口

比原在監(jiān)聽這個(gè)端口的時(shí)候,并不是如我最開始預(yù)期的直接調(diào)用net.Listen監(jiān)聽它。實(shí)際的過程要比這個(gè)復(fù)雜,因?yàn)楸仍O(shè)計(jì)了一個(gè)叫Switch的對象,用來統(tǒng)一管理與外界相關(guān)的事件,包括監(jiān)聽、連接、發(fā)送消息等。而Switch這個(gè)對象,又是在SyncManager中創(chuàng)建的。

啟動直到進(jìn)入Switch

所以我們首先需要知道,比原在源代碼中是如何啟動,并且一步步走進(jìn)了Switch的世界。

首先還是當(dāng)我們bytomd node啟動比原時(shí),對應(yīng)的入口函數(shù)如下:

cmd/bytomd/main.go#L54

func main() {
    cmd := cli.PrepareBaseCmd(commands.RootCmd, "TM", os.ExpandEnv(config.DefaultDataDir()))
    cmd.Execute()
}

它又會根據(jù)傳入的node參數(shù),運(yùn)行下面的函數(shù):

cmd/bytomd/commands/run_node.go#L41

func runNode(cmd *cobra.Command, args []string) error {
    // Create & start node
    n := node.NewNode(config)
    // ...
}

我們需要關(guān)注的是node.NewNode(config)函數(shù),因?yàn)槭窃谒锩鎰?chuàng)建了SyncManager

node/node.go#L59

func NewNode(config *cfg.Config) *Node {
    // ...
    syncManager, _ := netsync.NewSyncManager(config, chain, txPool, newBlockCh)
    // ...
}

在創(chuàng)建SyncManager的時(shí)候,又創(chuàng)建了Switch:

netsync/handle.go#L42

func NewSyncManager(config *cfg.Config, chain *core.Chain, txPool *core.TxPool, newBlockCh chan *bc.Hash) (*SyncManager, error) {
    // ...
    manager.sw = p2p.NewSwitch(config.P2P, trustHistoryDB)

    // ...
    protocolReactor := NewProtocolReactor(chain, txPool, manager.sw, manager.blockKeeper, manager.fetcher, manager.peers, manager.newPeerCh, manager.txSyncCh, manager.dropPeerCh)
    manager.sw.AddReactor("PROTOCOL", protocolReactor)

    // Create & add listener
    p, address := protocolAndAddress(manager.config.P2P.ListenAddress)
    l := p2p.NewDefaultListener(p, address, manager.config.P2P.SkipUPNP, nil)
    manager.sw.AddListener(l)

    // ...
}

這里需要注意一下,上面創(chuàng)建的protocolReactor對象,是用來處理當(dāng)有節(jié)點(diǎn)連接上端口后,雙方如何交互的事情。跟這次問題“監(jiān)聽端口”沒有直接關(guān)系,但是這里也可以注意一下。

然后又創(chuàng)建了一個(gè)DefaultListener對象,而監(jiān)聽端口的動作,就是在它里面發(fā)生的。Listener創(chuàng)建之后,將會添加到manager.sw(即Switch)中,用于在那邊進(jìn)行外界數(shù)據(jù)與事件的交互。

監(jiān)聽端口

NewDefaultListener中做的事情比較多,所以我們把它分成幾塊說:

p2p/listener.go#L52

func NewDefaultListener(protocol string, lAddr string, skipUPNP bool, logger tlog.Logger) Listener {
    // Local listen IP & port
    lAddrIP, lAddrPort := splitHostPort(lAddr)

    // Create listener
    var listener net.Listener
    var err error
    for i := 0; i < tryListenSeconds; i++ {
        listener, err = net.Listen(protocol, lAddr)
        if err == nil {
            break
        } else if i < tryListenSeconds-1 {
            time.Sleep(time.Second * 1)
        }
    }
    if err != nil {
        cmn.PanicCrisis(err)
    }

    // ...

上面這部分就是真正監(jiān)聽的代碼了。通過Go語言提供的net.Listen函數(shù),監(jiān)聽了指定的地址。另外,在監(jiān)聽的時(shí)候,進(jìn)行了多次嘗試,因?yàn)楫?dāng)一個(gè)剛剛被使用的端口被放開后,還需要一小段時(shí)間才能真正釋放,所以這里需要多嘗試幾次。

其中tryListenSeconds是一個(gè)常量,值為5,也就是說,大約會嘗試5秒鐘,要是都綁定不上,才會真正失敗,拋出錯(cuò)誤。

后面省略了一些代碼,主要是用來獲取當(dāng)前監(jiān)聽的實(shí)際ip以及外網(wǎng)ip,并記錄在日志中。本想在這里簡單講講,但是發(fā)現(xiàn)還有點(diǎn)麻煩,所以打算放在后面專開一個(gè)問題。

其實(shí)本次問題到這里就已經(jīng)結(jié)束了,因?yàn)橐呀?jīng)完成了“監(jiān)聽”。但是后面還有一些初始化操作,是為了讓比原可以跟連接上該端口的節(jié)點(diǎn)進(jìn)行交互,也值得在這里講講。

接著剛才的方法,最后的部分是:

    dl := &DefaultListener{
        listener:    listener,
        intAddr:     intAddr,
        extAddr:     extAddr,
        connections: make(chan net.Conn, numBufferedConnections),
    }
    dl.BaseService = *cmn.NewBaseService(logger, "DefaultListener", dl)
    dl.Start() // Started upon construction
    return dl
}

需要注意的是connections,它是一個(gè)帶有緩沖的channel(numBufferedConnections值為10),用來存放連接上該端口的連接對象。這些操作將在后面的dl.Start()中執(zhí)行。

dl.Start()將調(diào)用DefaultListener對應(yīng)的OnStart方法,如下:

p2p/listener.go#L114

func (l *DefaultListener) OnStart() error {
    l.BaseService.OnStart()
    go l.listenRoutine()
    return nil
}

其中的l.listenRoutine,就是執(zhí)行前面所說的向connections channel里放入連接的函數(shù):

p2p/listener.go#L126

func (l *DefaultListener) listenRoutine() {
    for {
        conn, err := l.listener.Accept()
        // ...
        l.connections <- conn
    }

    // Cleanup
    close(l.connections)

    // ...
}

SwitchSyncManager啟動的時(shí)候會被啟動,在它的OnStart方法中,會拿到所有Listener(即監(jiān)聽端口的對象)中connectionschannel中的連接,與它們交互。

https://github.com/freewind/b...

func (sw *Switch) listenerRoutine(l Listener) {
    for {
        inConn, ok := <-l.Connections()
        if !ok {
            break
        }
        // ...
        
        err := sw.addPeerWithConnectionAndConfig(inConn, sw.peerConfig)
        // ...
    }

其中sw.addPeerWithConnectionAndConfig就是與對應(yīng)節(jié)點(diǎn)進(jìn)行交互的邏輯所在,但是這已經(jīng)超出了本次問題的范疇,下次再講。

到此為止,本次的問題,應(yīng)該已經(jīng)講清楚了。

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

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

相關(guān)文章

  • 剝開原看代碼06:比原如何把請求區(qū)塊數(shù)據(jù)信息發(fā)出去

    摘要:作者比原項(xiàng)目倉庫地址地址在前一篇中,我們說到,當(dāng)比原向其它節(jié)點(diǎn)請求區(qū)塊數(shù)據(jù)時(shí),會發(fā)送一個(gè)把需要的區(qū)塊告訴對方,并把該信息對應(yīng)的二進(jìn)制數(shù)據(jù)放入對應(yīng)的通道中,等待發(fā)送。這個(gè)就是真正與連接對象綁定的一個(gè)緩存區(qū),寫入到它里面的數(shù)據(jù),會被發(fā)送出去。 作者:freewind 比原項(xiàng)目倉庫: Github地址:https://github.com/Bytom/bytom Gitee地址:https:...

    CloudwiseAPM 評論0 收藏0
  • 剝開原看代碼07:比原節(jié)點(diǎn)收到“請求區(qū)塊數(shù)據(jù)”信息后如何應(yīng)答?

    摘要:到這里,我們總算能夠完整的理解清楚,當(dāng)我們向一個(gè)比原節(jié)點(diǎn)請求區(qū)塊數(shù)據(jù),我們這邊需要怎么做,對方節(jié)點(diǎn)又需要怎么做了。 作者:freewind 比原項(xiàng)目倉庫: Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockc... 在上一篇,我們知道了比原是如何把請求區(qū)塊數(shù)據(jù)的信息BlockReque...

    233jl 評論0 收藏0
  • 剝開原看代碼01:初始化時(shí)生成配置文件在哪兒

    摘要:所以這個(gè)文章系列叫作剝開比原看代碼。所以我的問題是比原初始化時(shí),產(chǎn)生了什么樣的配置文件,放在了哪個(gè)目錄下下面我將結(jié)合源代碼,來回答這個(gè)問題。將用來確認(rèn)數(shù)據(jù)目錄是有效的,并且將根據(jù)傳入的不同,來生成不同的內(nèi)容寫入到配置文件中。 作者:freewind 比原項(xiàng)目倉庫: Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee...

    felix0913 評論0 收藏0
  • 剝開原看代碼10:比原如何通過/create-key接口創(chuàng)建密鑰

    摘要:如果傳的是,就會在內(nèi)部使用默認(rèn)的隨機(jī)數(shù)生成器生成隨機(jī)數(shù)并生成密鑰。使用的是,生成的是一個(gè)形如這樣的全球唯一的隨機(jī)數(shù)把密鑰以文件形式保存在硬盤上。 作者:freewind 比原項(xiàng)目倉庫: Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockc... 在前一篇,我們探討了從瀏覽器的dashb...

    ccj659 評論0 收藏0
  • 剝開原看代碼11:比原如何通過接口/create-account創(chuàng)建帳戶

    摘要:而本文將繼續(xù)討論,比原是如何通過接口來創(chuàng)建帳戶的。把各信息打包在一起,稱之為另外,在第處還是一個(gè)需要注意的。比原在代碼中使用它保存各種數(shù)據(jù),比如區(qū)塊帳戶等。到這里,我們已經(jīng)差不多清楚了比原的是如何根據(jù)用戶提交的參數(shù)來創(chuàng)建帳戶的。 作者:freewind 比原項(xiàng)目倉庫: Github地址:https://github.com/Bytom/bytom Gitee地址:https://git...

    haobowd 評論0 收藏0

發(fā)表評論

0條評論

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