go語言libp2p go語言適合做什么

如何看待go語言泛型的最新設(shè)計?

Go 由于不支持泛型而臭名昭著,但最近,泛型已接近成為現(xiàn)實。Go 團(tuán)隊實施了一個看起來比較穩(wěn)定的設(shè)計草案,并且正以源到源翻譯器原型的形式獲得關(guān)注。本文講述的是泛型的最新設(shè)計,以及如何自己嘗試泛型。

創(chuàng)新互聯(lián)專注于云岡企業(yè)網(wǎng)站建設(shè),自適應(yīng)網(wǎng)站建設(shè),成都商城網(wǎng)站開發(fā)。云岡網(wǎng)站建設(shè)公司,為云岡等地區(qū)提供建站服務(wù)。全流程定制網(wǎng)站開發(fā),專業(yè)設(shè)計,全程項目跟蹤,創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務(wù)

例子

FIFO Stack

假設(shè)你要創(chuàng)建一個先進(jìn)先出堆棧。沒有泛型,你可能會這樣實現(xiàn):

type?Stack?[]interface{}func?(s?Stack)?Peek()?interface{}?{

return?s[len(s)-1]

}

func?(s?*Stack)?Pop()?{

*s?=?(*s)[:

len(*s)-1]

}

func?(s?*Stack)?Push(value?interface{})?{

*s?=?

append(*s,?value)

}

但是,這里存在一個問題:每當(dāng)你 Peek 項時,都必須使用類型斷言將其從 interface{} 轉(zhuǎn)換為你需要的類型。如果你的堆棧是 *MyObject 的堆棧,則意味著很多 s.Peek().(*MyObject)這樣的代碼。這不僅讓人眼花繚亂,而且還可能引發(fā)錯誤。比如忘記 * 怎么辦?或者如果您輸入錯誤的類型怎么辦?s.Push(MyObject{})` 可以順利編譯,而且你可能不會發(fā)現(xiàn)到自己的錯誤,直到它影響到你的整個服務(wù)為止。

通常,使用 interface{} 是相對危險的。使用更多受限制的類型總是更安全,因為可以在編譯時而不是運行時發(fā)現(xiàn)問題。

泛型通過允許類型具有類型參數(shù)來解決此問題:

type?Stack(type?T)?[]Tfunc?(s?Stack(T))?Peek()?T?{

return?s[len(s)-1]

}

func?(s?*Stack(T))?Pop()?{

*s?=?(*s)[:

len(*s)-1]

}

func?(s?*Stack(T))?Push(value?T)?{

*s?=?

append(*s,?value)

}

這會向 Stack 添加一個類型參數(shù),從而完全不需要 interface{}。現(xiàn)在,當(dāng)你使用 Peek() 時,返回的值已經(jīng)是原始類型,并且沒有機(jī)會返回錯誤的值類型。這種方式更安全,更容易使用。(譯注:就是看起來更丑陋,^-^)

此外,泛型代碼通常更易于編譯器優(yōu)化,從而獲得更好的性能(以二進(jìn)制大小為代價)。如果我們對上面的非泛型代碼和泛型代碼進(jìn)行基準(zhǔn)測試,我們可以看到區(qū)別:

type?MyObject?struct?{

X?

int

}

var?sink?MyObjectfunc?BenchmarkGo1(b?*testing.B)?{

for?i?:=?0;?i??b.N;?i++?{

var?s?Stack

s.Push(MyObject{})

s.Push(MyObject{})

s.Pop()

sink?=?s.Peek().(MyObject)

}

}

func?BenchmarkGo2(b?*testing.B)?{

for?i?:=?0;?i??b.N;?i++?{

var?s?Stack(MyObject)

s.Push(MyObject{})

s.Push(MyObject{})

s.Pop()

sink?=?s.Peek()

}

}

結(jié)果:

BenchmarkGo1BenchmarkGo1-16?????12837528?????????87.0?ns/op???????48?B/op????????2?allocs/opBenchmarkGo2BenchmarkGo2-16?????28406479?????????41.9?ns/op???????24?B/op????????2?allocs/op

在這種情況下,我們分配更少的內(nèi)存,同時泛型的速度是非泛型的兩倍。

合約(Contracts)

上面的堆棧示例適用于任何類型。但是,在許多情況下,你需要編寫僅適用于具有某些特征的類型的代碼。例如,你可能希望堆棧要求類型實現(xiàn) String() 函數(shù)

IPFS(四) 源碼解讀之-p2p

package p2p

import (

"context"

"errors"

"time"

net "gx/ipfs/QmPjvxTpVH8qJyQDnxnsxF9kv9jezKD1kozz1hs3fCGsNh/go-libp2p-net"

manet "gx/ipfs/QmV6FjemM1K8oXjrvuq3wuVWWoU2TLDPmNnKrxHzY3v6Ai/go-multiaddr-net"

ma "gx/ipfs/QmYmsdtJ3HsodkePE3eU3TsCaP2YvPZJ4LoXnNkDE5Tpt7/go-multiaddr"

pro "gx/ipfs/QmZNkThpqfVXs9GNbexPrfBbXSLNYeKrE7jwFM2oqHbyqN/go-libp2p-protocol"

pstore "gx/ipfs/QmZR2XWVVBCtbgBWnQhWk2xcQfaR3W8faQPriAiaaj7rsr/go-libp2p-peerstore"

p2phost "gx/ipfs/Qmb8T6YBBsjYsVGfrihQLfCJveczZnneSBqBKkYEBWDjge/go-libp2p-host"

peer "gx/ipfs/QmdVrMn1LhB4ybb8hMVaMLXnA8XRSewMnK6YqXKXoTcRvN/go-libp2p-peer"

)

//P2P結(jié)構(gòu)保存當(dāng)前正在運行的流/監(jiān)聽器的信息

// P2P structure holds information on currently running streams/listeners

type P2P struct {

//監(jiān)聽器

Listeners ListenerRegistry

//數(shù)據(jù)流

Streams StreamRegistry

//節(jié)點ID

identity peer.ID

//節(jié)點地址

peerHost p2phost.Host

//一個線程安全的對等節(jié)點存儲

peerstore pstore.Peerstore

}

//創(chuàng)建一個新的p2p結(jié)構(gòu)

// NewP2P creates new P2P struct

//這個新的p2p結(jié)構(gòu)不包含p2p結(jié)構(gòu)中的監(jiān)聽器和數(shù)據(jù)流

func NewP2P(identity peer.ID, peerHost p2phost.Host, peerstore pstore.Peerstore) *P2P {

return P2P{

identity: identity,

peerHost: peerHost,

peerstore: peerstore,

}

}

//新建一個數(shù)據(jù)流 工具方法 構(gòu)建一個有節(jié)點id,內(nèi)容和協(xié)議的流

func (p2p P2P) newStreamTo(ctx2 context.Context, p peer.ID, protocol string) (net.Stream, error) {

//30s 后會自動timeout

ctx, cancel := context.WithTimeout(ctx2, time.Second 30) //TODO: configurable?

defer cancel()

err := p2p.peerHost.Connect(ctx, pstore.PeerInfo{ID: p})

if err != nil {

return nil, err

}

return p2p.peerHost.NewStream(ctx2, p, pro.ID(protocol))

}

//對話為遠(yuǎn)程監(jiān)聽器創(chuàng)建新的P2P流

//創(chuàng)建一個新的p2p流實現(xiàn)對對話的監(jiān)聽

// Dial creates new P2P stream to a remote listener

//Multiaddr是一種跨協(xié)議、跨平臺的表示格式的互聯(lián)網(wǎng)地址。它強(qiáng)調(diào)明確性和自我描述。

//對內(nèi)接收

func (p2p P2P) Dial(ctx context.Context, addr ma.Multiaddr, peer peer.ID, proto string, bindAddr ma.Multiaddr) ( ListenerInfo, error) {

//獲取一些節(jié)點信息 network, host, nil

lnet, _, err := manet.DialArgs(bindAddr)

if err != nil {

return nil, err

}

//監(jiān)聽信息

listenerInfo := ListenerInfo{

//節(jié)點身份

Identity: p2p.identity,

////應(yīng)用程序協(xié)議標(biāo)識符。

Protocol: proto,

}

//調(diào)用newStreamTo 通過ctx(內(nèi)容) peer(節(jié)點id) proto(協(xié)議標(biāo)識符) 參數(shù)獲取一個新的數(shù)據(jù)流

remote, err := p2p.newStreamTo(ctx, peer, proto)

if err != nil {

return nil, err

}

//network協(xié)議標(biāo)識

switch lnet {

//network為"tcp", "tcp4", "tcp6"

case "tcp", "tcp4", "tcp6":

//從監(jiān)聽器獲取新的信息 nla.Listener, nil

listener, err := manet.Listen(bindAddr)

if err != nil {

if err2 := remote.Reset(); err2 != nil {

return nil, err2

}

return nil, err

}

//將獲取的新信息保存到listenerInfo

listenerInfo.Address = listener.Multiaddr()

listenerInfo.Closer = listener

listenerInfo.Running = true

//開啟接受

go p2p.doAccept(listenerInfo, remote, listener)

default:

return nil, errors.New("unsupported protocol: " + lnet)

}

return listenerInfo, nil

}

//

func (p2p *P2P) doAccept(listenerInfo *ListenerInfo, remote net.Stream, listener manet.Listener) {

//關(guān)閉偵聽器并刪除流處理程序

defer listener.Close()

//Returns a Multiaddr friendly Conn

//一個有好的 Multiaddr 連接

local, err := listener.Accept()

if err != nil {

return

}

stream := StreamInfo{

//連接協(xié)議

Protocol: listenerInfo.Protocol,

//定位節(jié)點

LocalPeer: listenerInfo.Identity,

//定位節(jié)點地址

LocalAddr: listenerInfo.Address,

//遠(yuǎn)程節(jié)點

RemotePeer: remote.Conn().RemotePeer(),

//遠(yuǎn)程節(jié)點地址

RemoteAddr: remote.Conn().RemoteMultiaddr(),

//定位

Local: local,

//遠(yuǎn)程

Remote: remote,

//注冊碼

Registry: p2p.Streams,

}

//注冊連接信息

p2p.Streams.Register(stream)

//開啟節(jié)點廣播

stream.startStreaming()

}

//偵聽器將流處理程序包裝到偵聽器中

// Listener wraps stream handler into a listener

type Listener interface {

Accept() (net.Stream, error)

Close() error

}

//P2PListener保存關(guān)于偵聽器的信息

// P2PListener holds information on a listener

type P2PListener struct {

peerHost p2phost.Host

conCh chan net.Stream

proto pro.ID

ctx context.Context

cancel func()

}

//等待偵聽器的連接

// Accept waits for a connection from the listener

func (il *P2PListener) Accept() (net.Stream, error) {

select {

case c := -il.conCh:

return c, nil

case -il.ctx.Done():

return nil, il.ctx.Err()

}

}

//關(guān)閉偵聽器并刪除流處理程序

// Close closes the listener and removes stream handler

func (il *P2PListener) Close() error {

il.cancel()

il.peerHost.RemoveStreamHandler(il.proto)

return nil

}

// Listen創(chuàng)建新的P2PListener

// Listen creates new P2PListener

func (p2p P2P) registerStreamHandler(ctx2 context.Context, protocol string) ( P2PListener, error) {

ctx, cancel := context.WithCancel(ctx2)

list := P2PListener{

peerHost: p2p.peerHost,

proto: pro.ID(protocol),

conCh: make(chan net.Stream),

ctx: ctx,

cancel: cancel,

}

p2p.peerHost.SetStreamHandler(list.proto, func(s net.Stream) {

select {

case list.conCh - s:

case -ctx.Done():

s.Reset()

}

})

return list, nil

}

// NewListener創(chuàng)建新的p2p偵聽器

// NewListener creates new p2p listener

//對外廣播

func (p2p P2P) NewListener(ctx context.Context, proto string, addr ma.Multiaddr) ( ListenerInfo, error) {

//調(diào)用registerStreamHandler 構(gòu)造一個新的listener

listener, err := p2p.registerStreamHandler(ctx, proto)

if err != nil {

return nil, err

}

//構(gòu)造新的listenerInfo

listenerInfo := ListenerInfo{

Identity: p2p.identity,

Protocol: proto,

Address: addr,

Closer: listener,

Running: true,

Registry: p2p.Listeners,

}

go p2p.acceptStreams(listenerInfo, listener)

//注冊連接信息

p2p.Listeners.Register(listenerInfo)

return listenerInfo, nil

}

//接受流

func (p2p *P2P) acceptStreams(listenerInfo *ListenerInfo, listener Listener) {

for listenerInfo.Running {

//一個有好的 遠(yuǎn)程 連接

remote, err := listener.Accept()

if err != nil {

listener.Close()

break

}

}

//取消注冊表中的p2p偵聽器

p2p.Listeners.Deregister(listenerInfo.Protocol)

}

// CheckProtoExists檢查是否注冊了協(xié)議處理程序

// mux處理程序

// CheckProtoExists checks whether a protocol handler is registered to

// mux handler

func (p2p *P2P) CheckProtoExists(proto string) bool {

protos := p2p.peerHost.Mux().Protocols()

for _, p := range protos {

if p != proto {

continue

}

return true

}

return false

}

IPFS 一個分布式系統(tǒng),用于存儲和訪問文件、網(wǎng)站、應(yīng)用程序和數(shù)據(jù)

《開源精選》是我們分享Github、Gitee等開源社區(qū)中優(yōu)質(zhì)項目的欄目,包括技術(shù)、學(xué)習(xí)、實用與各種有趣的內(nèi)容。本期推薦的IPFS 是一個分布式系統(tǒng),用于存儲和訪問文件、網(wǎng)站、應(yīng)用程序和數(shù)據(jù)。

而且,當(dāng)您使用 IPFS 時,您不只是從其他人那里下載文件——您的計算機(jī)也有助于分發(fā)它們。當(dāng)您在幾個街區(qū)外的朋友需要相同的 Wikipedia 頁面時,他們可能會像從您的鄰居或任何使用 IPFS 的人那里一樣從您那里獲得它。

IPFS 不僅可以用于網(wǎng)頁,還可以用于計算機(jī)可能存儲的任何類型的文件,無論是文檔、電子郵件,甚至是數(shù)據(jù)庫記錄。

可以從不由一個組織管理的多個位置下載文件:

最后一點實際上是 IPFS 的全名: InterPlanetary File System 。我們正在努力建立一個系統(tǒng),該系統(tǒng)可以在不連貫或相隔很遠(yuǎn)的地方工作,就像行星一樣。雖然這是一個理想主義的目標(biāo),但它讓我們努力工作和思考,幾乎我們?yōu)閷崿F(xiàn)這一目標(biāo)而創(chuàng)造的一切在家里也很有用。

IPFS 是一個點對點 (p2p) 存儲網(wǎng)絡(luò)??梢酝ㄟ^位于世界任何地方的對等點訪問內(nèi)容,這些對等點可能會傳遞信息、存儲信息或兩者兼而有之。IPFS 知道如何使用其內(nèi)容地址而不是其位置來查找您要求的內(nèi)容。

理解 IPFS 的三個基本原則:

這三個原則相互依賴,以啟用 IPFS 生態(tài)系統(tǒng)。讓我們從 內(nèi)容尋址 和內(nèi)容的唯一標(biāo)識開始。

互聯(lián)網(wǎng)和您的計算機(jī)上都存在這個問題!現(xiàn)在,內(nèi)容是按位置查找的,例如:

相比之下,每條使用 IPFS 協(xié)議的內(nèi)容都有一個 內(nèi)容標(biāo)識符 ,即 CID,即其 哈希值 。散列對于它所來自的內(nèi)容來說是唯一的,即使它與原始內(nèi)容相比可能看起來很短。

有向無環(huán)圖 (DAG)

IPFS 和許多其他分布式系統(tǒng)利用稱為有向無環(huán)圖的數(shù)據(jù)結(jié)構(gòu) (打開新窗口),或 DAG。具體來說,他們使用 Merkle DAG ,其中每個節(jié)點都有一個唯一標(biāo)識符,該標(biāo)識符是節(jié)點內(nèi)容的哈希。

IPFS 使用針對表示目錄和文件進(jìn)行了優(yōu)化的 Merkle DAG,但您可以通過多種不同的方式構(gòu)建 Merkle DAG。例如,Git 使用 Merkle DAG,其中包含許多版本的存儲庫。

為了構(gòu)建內(nèi)容的 Merkle DAG 表示,IPFS 通常首先將其拆分為 塊 。將其拆分為塊意味著文件的不同部分可以來自不同的來源并可以快速進(jìn)行身份驗證。

分布式哈希表 (DHT)

要查找哪些對等方正在托管您所追求的內(nèi)容( 發(fā)現(xiàn) ),IPFS 使用分布式哈希表或 DHT。哈希表是值鍵的數(shù)據(jù)庫。 分布式 哈希表是一種表在分布式網(wǎng)絡(luò)中的所有對等方之間拆分的表。要查找內(nèi)容,您需要詢問這些同行。

libp2p項目 (打開新窗口)是 IPFS 生態(tài)系統(tǒng)的一部分,它提供 DHT 并處理對等點之間的連接和交談。

一旦你知道你的內(nèi)容在哪里(或者更準(zhǔn)確地說,哪些對等點正在存儲構(gòu)成你所追求的內(nèi)容的每個塊),你就可以再次使用 DHT 來查找這些對等點的當(dāng)前位置( 路由 )。因此,要獲取內(nèi)容,請使用 libp2p 查詢 DHT 兩次。

然而,這確實意味著 IPFS 本身并沒有明確保護(hù) 有關(guān) CID 和提供或檢索它們的節(jié)點的知識。這不是分布式網(wǎng)絡(luò)所獨有的。在 d-web 和 legacy web 上,流量和其他元數(shù)據(jù)都可以通過可以推斷出很多關(guān)于網(wǎng)絡(luò)及其用戶的方式進(jìn)行監(jiān)控。下面概述了這方面的一些關(guān)鍵細(xì)節(jié),但簡而言之:雖然 節(jié)點之間 的 IPFS 流量是加密的,但這些節(jié)點發(fā)布到 DHT 的元數(shù)據(jù)是公開的。節(jié)點宣布對 DHT 功能至關(guān)重要的各種信息——包括它們的唯一節(jié)點標(biāo)識符 (PeerID) 和它們提供的數(shù)據(jù)的 CID——因此,關(guān)于哪些節(jié)點正在檢索和/或重新提供哪些 CID 的信息是公開的可用的。

加密

網(wǎng)絡(luò)中有兩種類型的加密: 傳輸加密 和 內(nèi)容加密 。

在兩方之間發(fā)送數(shù)據(jù)時使用傳輸加密。阿爾伯特加密文件并將其發(fā)送給萊卡,萊卡在收到文件后對其進(jìn)行解密。這會阻止第三方在數(shù)據(jù)從一個地方移動到另一個地方時查看數(shù)據(jù)。

內(nèi)容加密用于保護(hù)數(shù)據(jù),直到有人需要訪問它。Albert 為他的每月預(yù)算創(chuàng)建了一個電子表格,并用密碼保存它。當(dāng) Albert 需要再次訪問它時,他必須輸入密碼才能解密文件。沒有密碼,Laika 無法查看該文件。

IPFS 使用傳輸加密,但不使用內(nèi)容加密。這意味著您的數(shù)據(jù)在從一個 IPFS 節(jié)點發(fā)送到另一個節(jié)點時是安全的。但是,如果擁有 CID,任何人都可以下載和查看該數(shù)據(jù)。缺乏內(nèi)容加密是一個有意的決定。您可以自由選擇最適合您的項目的方法,而不是強(qiáng)迫您使用特定的加密協(xié)議。

如果您精通命令行并且只想立即啟動并運行 IPFS,請遵循此快速入門指南。請注意,本指南假定您將安裝 go-ipfs,這是用 Go 編寫的參考實現(xiàn)。

ipfs將其所有設(shè)置和內(nèi)部數(shù)據(jù)存儲在稱為 存儲庫的目錄中。 在第一次使用 IPFS 之前,您需要使用以下ipfs init命令初始化存儲庫:

如果您在數(shù)據(jù)中心的服務(wù)器上運行,則應(yīng)使用server配置文件初始化 IPFS。這樣做會阻止 IPFS 創(chuàng)建大量數(shù)據(jù)中心內(nèi)部流量來嘗試發(fā)現(xiàn)本地節(jié)點:

您可能需要設(shè)置大量其他配置選項 — 查看完整參考 (打開新窗口)更多。

后面的散列peer identity:是您節(jié)點的 ID,與上面輸出中顯示的不同。網(wǎng)絡(luò)上的其他節(jié)點使用它來查找并連接到您。如果需要,您可以隨時運行ipfs id以再次獲取它。

現(xiàn)在,嘗試運行在ipfs init. 那個樣子ipfs cat /ipfs/ /readme。

您應(yīng)該看到如下內(nèi)容:

您可以 探索 存儲庫中的其他對象。特別是quick-start顯示示例命令嘗試的目錄:

準(zhǔn)備好將節(jié)點加入公共網(wǎng)絡(luò)后,在另一個終端中運行 ipfs 守護(hù)程序,并等待以下所有三行顯示您的節(jié)點已準(zhǔn)備好:

記下您收到的 TCP 端口。如果它們不同,請在下面的命令中使用您的。

現(xiàn)在,切換回原來的終端。如果您已連接到網(wǎng)絡(luò),您應(yīng)該能夠在運行時看到對等方的 IPFS 地址:

這些是 /p2p/ .

現(xiàn)在,您應(yīng)該能夠從網(wǎng)絡(luò)中獲取對象了。嘗試:

使用上述命令,IPFS 在網(wǎng)絡(luò)中搜索 CIDQmSgv...并將數(shù)據(jù)寫入spaceship-launch.jpg桌面上調(diào)用的文件中。

接下來,嘗試將對象發(fā)送到網(wǎng)絡(luò),然后在您喜歡的瀏覽器中查看它。以下示例curl用作瀏覽器,但您也可以在其他瀏覽器中打開 IPFS URL:

您可以通過轉(zhuǎn)到 來查看本地節(jié)點上的 Web 控制臺localhost:5001/webui。這應(yīng)該會彈出一個這樣的控制臺:

Web 控制臺顯示可變文件系統(tǒng) (MFS)中的文件。MFS 是內(nèi)置于 Web 控制臺的工具,可幫助您以與基于名稱的文件系統(tǒng)相同的方式導(dǎo)航 IPFS 文件。

當(dāng)您使用CLI 命令ipfs add ...添加文件時,這些文件不會自動在 MFS 中可用。要查看您使用 CLI 添加的 IPFS 桌面中的文件,您必須將文件復(fù)制到 MFS:

—END—

開源協(xié)議:MIT License

開源地址:

網(wǎng)站標(biāo)題:go語言libp2p go語言適合做什么
網(wǎng)頁網(wǎng)址:http://bm7419.com/article2/ddeppic.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站制作、網(wǎng)站營銷、定制網(wǎng)站搜索引擎優(yōu)化、面包屑導(dǎo)航虛擬主機(jī)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都app開發(fā)公司