当前位置:网站首页>Rust P2P Network Application Combat-1 P2P Network Core Concepts and Ping Program
Rust P2P Network Application Combat-1 P2P Network Core Concepts and Ping Program
2022-08-02 01:41:00 【Coding to dim lights】
本系列文章首先研究P2P网络的核心概念,然后详细分析libp2p-rust库中的应用实例,为以后开发P2P网络应用程序打好基础.
P2P网络
P2P(Peer-to-Peer)是一种网络技术,可以在网络中不同的计算机上共享各种计算资源,如CPU、网络带宽和存储等.P2P技术应用最广泛的是在网络中共享文件以及区块链网络,它们不依赖中央服务器或中介来连接多个客户端,用户的计算机即是客户端也是服务器.
由于P2P网络是一种分布式系统,不会像中央服务器一样存在单点故障,因此容错性极强.

下面让我们来看一看P2P网络的核心概念:
传输协议
在P2P网络底层一般使用TCP/UDP传输层协议.由于P2P节点应用的多样性,在TCP/UDP传输层协议之上,会使用多种应用层协议,如:HTTP,gRPC及自定义协议等.为了有效利用资源,P2P网络会在一个连接上监听、解析多种协议,即多路复用技术:多个逻辑子流可以在同一个底层(TCP)连接上共存.可以查看yamux 库了解更多细节.
节点标识
P2P网络中的节点需要一个唯一的标识,以便其他节点能够找到它们.P2P网络中的节点使用公钥和私钥对(非对称公钥加密)与其他节点建立安全通信.在P2P网络中节点标识被称为PeerId,它是通过对节点公钥进行加密哈希得到的.
安全规则
密钥对和节点身份标识使节点之间能够体建立安全的、经过身份验证的通信通道.但这只是安全的一个方面,节点还需要根据业务逻辑实现授权框架,该框架建立一些规则:哪些节点可以执行哪种类型的操作等.
节点路由
P2P网络中的一个节点首先需要找到其他节点来进行通信.这是通过维护一个节点路由表来实现的.但是在P2P网络中,有成千上万个节点在动态变化(即节点的加入和离开),单个节点很难为网络中的所有节点维护一个完整、准确的路由表.所以节点路由表通常会由一系列路由节点维护.
消息
P2P网络中的节点可以向特定节点发送消息,也可以广播消息.使用发布/订阅模式,节点订阅感兴趣Topic,所有订阅该Topic的节点都能接收和发送消息.这种技术也通常用于将消息的内容传输到整个网络.
流多路复用
在P2P网络中,允许多个独立的“逻辑”流共享一个公共的P2P传输层.流多路复用有助于优化节点之间建立网络连接的开销.多路复用在后端服务开发中很常见,客户端可以与服务器建立底层网络连接,然后在底层网络连接上复用不同的流.
libp2p
自己编写P2P应用程序的网络层是一项庞大的工程,我们将使用底层p2p网络库—libp2p,在其上构建p2p应用程序会更加容易.libp2p是一个模块化的系统,支持三种编程语言:Rust、Go、JS.许多流行的项目中都使用libp2p做为P2P网络底层,如IPFS、 Filecoin、Polkadot和Substrate.
libp2p将P2P网络基本概念分解成了不同的模块,可以在不同的应用场景中组合使用.
我们先通过Ping这个简单的程序来熟悉一下libp2p的组件及如何使用libp2p开发点对点网络.
PING
这个例子非常简单,主要就是一个节点向另一个节点发送ping消息,然后等待另一个节点返回pong消息.
新建一个项目名叫:libp2p-learn
master:p2p Justin$ cargo new libp2p-learn
Created binary (application) `libp2p-learn` package
master:p2p Justin$ cd libp2p-learn/
master:libp2p-learn Justin$ code .在Cargo.toml文件中加入libp2p和tokio依赖:
[dependencies]
libp2p = "0.46"
tokio = { version = "1.19", features = ["full"] }然后在src/bin/目录下创建ping.rs文件:
use std::error::Error;
use libp2p::{
futures::StreamExt,
identity,
ping::{Ping, PingConfig},
swarm::SwarmEvent,
Multiaddr, PeerId, Swarm,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
// 生成密钥对
let key_pair = identity::Keypair::generate_ed25519();
// 基于密钥对的公钥,生成节点唯一标识peerId
let peer_id = PeerId::from(key_pair.public());
println!("节点ID: {peer_id}");
// 声明Ping网络行为
let behaviour = Ping::new(PingConfig::new().with_keep_alive(true));
// 传输
let transport = libp2p::development_transport(key_pair).await?;
// 网络管理模块
let mut swarm = Swarm::new(transport, behaviour, peer_id);
// 在节点随机开启一个端口监听
swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?;
// 从命令行参数获取远程节点地址,进行链接.
if let Some(remote_peer) = std::env::args().nth(1) {
let remote_peer_multiaddr: Multiaddr = remote_peer.parse()?;
swarm.dial(remote_peer_multiaddr)?;
println!("链接远程节点: {remote_peer}");
}
loop {
// 匹配网络事件
match swarm.select_next_some().await {
// 监听事件
SwarmEvent::NewListenAddr { address, .. } => {
println!("本地监听地址: {address}");
}
// 网络行为事件
SwarmEvent::Behaviour(event) => println!("{:?}", event),
_ => {}
}
}
}- 网络行为Behaviour:传输(transport)定义如何在网络中发送字节流,而网络行为定义发送什么样的字节流,在这里我们发送ping/pong消息.
- 网络管理模块Swarm:用于管理节点之间的所有活跃连接和挂起连接,并管理所有已打开的子流状态.Swarm是通过传输、网络行为和节点PeerId来创建.
- 节点地址:/ip4/0.0.0.0/tcp/0,表示在本机所有ip地址上,开一个随机的Tcp端口进行监听.
打开一个终端,运行:
cargo run --bin pingmaster:libp2p-learn Justin$ cargo run --bin ping
Compiling libp2p-learn v0.1.0 (/Users/Justin/workspace_rust_exercise/network-study/p2p/libp2p-learn)
Finished dev [unoptimized + debuginfo] target(s) in 8.65s
Running `target/debug/ping`
节点ID: 12D3KooWR7H9SwB2yiFBKvzcVGFdpeKmuFG9qDTBTvuuuDarASST
本地监听地址: /ip4/127.0.0.1/tcp/58645可以看到已经打印出PeerId和监听地址.
打开另一个终端,运行:
cargo run --bin ping /ip4/127.0.0.1/tcp/58645master:libp2p-learn Justin$ cargo run --bin ping /ip4/127.0.0.1/tcp/58645
Finished dev [unoptimized + debuginfo] target(s) in 0.36s
Running `target/debug/ping /ip4/127.0.0.1/tcp/58645`
节点ID: 12D3KooWCUFTHNMJrR1p8vkFEFFYm4J8iPA1Wh6x2Dya5qmU1xdL
链接远程节点: /ip4/127.0.0.1/tcp/58645
本地监听地址: /ip4/127.0.0.1/tcp/58727
Event { peer: PeerId("12D3KooWR7H9SwB2yiFBKvzcVGFdpeKmuFG9qDTBTvuuuDarASST"), result: Ok(Pong) }
Event { peer: PeerId("12D3KooWR7H9SwB2yiFBKvzcVGFdpeKmuFG9qDTBTvuuuDarASST"), result: Ok(Ping { rtt: 1.234008ms }) }我们可以看到链接到刚刚的节点/ip4/127.0.0.1/tcp/58645成功,也收到了发送过来的ping/pong的消息.
下一篇文章我们将详细解析P2P聊天程序.
更多文章,请关注公众号:coding到灯火阑珊

边栏推荐
- 喜报 | AR 开启纺织产业新模式,ALVA Systems 再获殊荣!
- Anti-oversold and high concurrent deduction scheme for e-commerce inventory system
- PHP直播源码实现简单弹幕效果的相关代码
- 【服务器数据恢复】服务器Raid5阵列mdisk磁盘离线的数据恢复案例
- Day115.尚医通:后台用户管理:用户锁定解锁、详情、认证列表审批
- hash table
- IDEA找不到Database解决方法
- dayjs时间处理库的基本使用
- 设备树学习
- ImportError cannot import name ‘Mapping‘ from ‘collections‘
猜你喜欢

Flex布局详解

Maxwell 一款简单易上手的实时抓取Mysql数据的软件

Can‘t connect to MySQL server on ‘localhost3306‘ (10061) 简洁明了的解决方法

Go语学习笔记 - gorm使用 - gorm处理错误 Web框架Gin(十)

Oracle data to mysql FlinkSQL CDC to achieve synchronization

YGG 公会发展计划第 1 季总结

字节给我狠狠上了一课:危机来的时候你连准备时间都没有...

Kubernetes之本地存储

typescript36-class的构造函数实例方法

Local storage in Kubernetes
随机推荐
【ORB_SLAM2】void Frame::AssignFeaturesToGrid()
Kubernetes — Flannel
Image fusion based on weighted 】 and pyramid image fusion with matlab code
Can't connect to MySQL server on 'localhost3306' (10061) Simple and clear solution
有效进行自动化测试,这几个软件测试工具一定要收藏好!!!
Mapped Statements collection does not contain value for的解决方法
安全(1)
Reflex WMS中阶系列7:已经完成拣货尚未Load的HD如果要取消拣货,该如何处理?
Some insights from 5 years of automated testing experience: UI automation must overcome these 10 pits
Debian侵犯Rust商标,妥协改名还是会得到豁免?
理解分布式系统中的缓存架构(下)
ERROR 2003 (HY000) Can‘t connect to MySQL server on ‘localhost3306‘ (10061)
Flex布局详解
【图像融合】基于加权和金字塔实现图像融合附matlab代码
简单工厂模式
浅谈国产ERP的“横纵竖”三向发展态势
HSDC和独立生成树相关
设备树学习
Kubernetes — 网络流量模型
C语言实验六 一维数组程序设计