深入理解 IPFS - DHT 网络(1)

2023-12-26 13:38
文章标签 深入 理解 网络 ipfs dht

本文主要是介绍深入理解 IPFS - DHT 网络(1),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在前面的文章中,我们说过,DHT(分布式哈希表)是 IPFS 一个重要的组成部分,接下来我们会分别从应用,原理两个方面来分析 DHT。

IPFS 的网络层源码在 libp2p 中,本文用 go-libp2p 做分析。

我们假设一个场景应用,有两个节点名字分别叫 earth 和 mars,然后他们分别加入了 DHT 网络,接下来他们需要找到对方,并能够互相发送消息。

 (一)初始化节点

首先我们需要初始化节点

1
2
3
4
ctx := context.Background()
listenAddresses, _ := multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/8004")
host, _ := libp2p.New(ctx, libp2p.ListenAddrs([]multiaddr.Multiaddr{listenAddresses}...))
fmt.Println("host->", host.ID())

其实初始化就一行 libp2p.New(),可自定义参数,比如上面我们定义了监听地址和端口 /ip4/127.0.0.1/tcp/8004, 等同于 127.0.0.1:8004 不过自解释性更强。

再举个例子,/ip4/1.2.3.4/tcp/4321/p2p/QmcEPrat8ShnCph8WjkREzt5CPXF2RwhYxYBALDcLC1iV6 结尾有个 PeerId QmcEPrat8ShnCph8WjkREzt5CPXF2RwhYxYBALDcLC1iV6

那么不仅仅可以通过 ip + port 寻址,通过 PeerId 也可以直接定位到节点。

初始化后我们生成了一个节点,节点 ID 以 btc58encode 编码:QmcEPrat8ShnCph8WjkREzt5CPXF2RwhYxYBALDcLC1iV6,也就是上文的 PeerID。

接下来我们需要给 8004 监听的端口配置 handler

1
2
3
4
5
func handleStream(stream network.Stream) {log.Println("Got a new stream!", stream)
}host.SetStreamHandler(protocol.ID('/chat/1.0'), handleStream)

handleStream 这个函数的逻辑跟普通的 socket 编程一样,拿到 stream 往里读写数据就行,这里不细讲。

(二)加入 DHT 网络

节点建立完成后,接下来就需要加入 DHT 网络了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 加入 dht 网络
kademliaDHT, err := dht.New(ctx, host)
if err != nil {panic(err)
}
// 设置状态为 bootstrap 模式
if err = kademliaDHT.Bootstrap(ctx); err != nil {panic(err)
}var wg sync.WaitGroup
// connect 到 bootstrap 节点
for _, peerAddr := range dht.DefaultBootstrapPeers {peerinfo, _ := peer.AddrInfoFromP2pAddr(peerAddr)wg.Add(1)go func() {defer wg.Done()if err := host.Connect(ctx, *peerinfo); err !=nil {log.Println(err)} else {log.Println("Connection established with bootstrap node:", *peerinfo)}}()
}
wg.Wait()

不管是比特币,以太坊,还是早前的 BT 网络,任何新节点加入网络都需要种子 (bootstrap) 节点作为起点,然后扩展自己的路由表,完成初始化动作。

(三)广而告之

1
2
3
4
5
6
// 广而告之
nodeName := "mars"
log.Println("Announcing ourselves...")
routingDiscovery := discovery.NewRoutingDiscovery(kademliaDHT)
discovery.Advertise(ctx, routingDiscovery, nodeName)
log.Println("Successfully announced!")

回到我们开头的场景,假设我们初始化一个节点名叫 mars,我们加入 DHT 网络后,需要让所有节点都知道我是 mars 节点 。

这里先简单介绍下,原理下篇文章再分析。nodeName 其实最后被转换为一个内容的 hash,节点通过 Advertise 这个方法告诉其他节点,它拥有这个 hash,然后其他节点就会记住,更新自己的路由表。等到有请求去做这个内容的寻址时,就会告诉对方谁有这个内容,或者谁和这个内容更接近。

(四)寻找节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
findName := "earth"
log.Println("Searching for other peers...")
peerChan, err := routingDiscovery.FindPeers(ctx, findName)
if err != nil {panic(err)
}
for peer := range peerChan {fmt.Println("found peer", peer.ID)if peer.ID == host.ID() {continue}stream, _ := host.NewStream(ctx, peer.ID, protocol.ID("/chat/1.0.0"))rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream))go readData(rw)go writeData(rw)
}

FindPeers 内在实现逻辑其实是找 earth 这个 hash 的地址,找到就和他建立一个双工的连接,正好和前面 handleStream 实现了服务端和客户端的通信。

(五)演示

 (六) 完善

上面的例子有个问题是,谁都可以宣称自己是 mars 节点,通信双方没法信任,所以这种模式适用聊天室的 channel 场景。通过将内容寻址改成节点寻址,就可找到可信通信方,当然前提是你知道你要通信的节点 ID。

代码如下:

1
2
findID, err := peer.Decode("QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dw1")
kademliaDHT.FindPeer(ctx, findID)

这篇关于深入理解 IPFS - DHT 网络(1)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/539619

相关文章

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

认识、理解、分类——acm之搜索

普通搜索方法有两种:1、广度优先搜索;2、深度优先搜索; 更多搜索方法: 3、双向广度优先搜索; 4、启发式搜索(包括A*算法等); 搜索通常会用到的知识点:状态压缩(位压缩,利用hash思想压缩)。

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

ASIO网络调试助手之一:简介

多年前,写过几篇《Boost.Asio C++网络编程》的学习文章,一直没机会实践。最近项目中用到了Asio,于是抽空写了个网络调试助手。 开发环境: Win10 Qt5.12.6 + Asio(standalone) + spdlog 支持协议: UDP + TCP Client + TCP Server 独立的Asio(http://www.think-async.com)只包含了头文件,不依

poj 3181 网络流,建图。

题意: 农夫约翰为他的牛准备了F种食物和D种饮料。 每头牛都有各自喜欢的食物和饮料,而每种食物和饮料都只能分配给一头牛。 问最多能有多少头牛可以同时得到喜欢的食物和饮料。 解析: 由于要同时得到喜欢的食物和饮料,所以网络流建图的时候要把牛拆点了。 如下建图: s -> 食物 -> 牛1 -> 牛2 -> 饮料 -> t 所以分配一下点: s  =  0, 牛1= 1~

【C++高阶】C++类型转换全攻略:深入理解并高效应用

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C++ “ 登神长阶 ” 🤡往期回顾🤡:C++ 智能指针 🌹🌹期待您的关注 🌹🌹 ❀C++的类型转换 📒1. C语言中的类型转换📚2. C++强制类型转换⛰️static_cast🌞reinterpret_cast⭐const_cast🍁dynamic_cast 📜3. C++强制类型转换的原因📝

poj 3068 有流量限制的最小费用网络流

题意: m条有向边连接了n个仓库,每条边都有一定费用。 将两种危险品从0运到n-1,除了起点和终点外,危险品不能放在一起,也不能走相同的路径。 求最小的费用是多少。 解析: 抽象出一个源点s一个汇点t,源点与0相连,费用为0,容量为2。 汇点与n - 1相连,费用为0,容量为2。 每条边之间也相连,费用为每条边的费用,容量为1。 建图完毕之后,求一条流量为2的最小费用流就行了

poj 2112 网络流+二分

题意: k台挤奶机,c头牛,每台挤奶机可以挤m头牛。 现在给出每只牛到挤奶机的距离矩阵,求最小化牛的最大路程。 解析: 最大值最小化,最小值最大化,用二分来做。 先求出两点之间的最短距离。 然后二分匹配牛到挤奶机的最大路程,匹配中的判断是在这个最大路程下,是否牛的数量达到c只。 如何求牛的数量呢,用网络流来做。 从源点到牛引一条容量为1的边,然后挤奶机到汇点引一条容量为m的边