当前位置: 首页 > news >正文

p2p、分布式,区块链笔记:libp2p通过libp2p_demo::network实现文件传递功能

代码

  • 代码来自github开源项目file-sharing.rs。主要依赖clap库进行命令行参数解析,使用async_std进行并行操作,使用libp2p_demo::network中的相关方法进行网络建立与文件传输,但是代码量却减少了很多,这是由于libp2p_demo::network对libp2p中的集群事件等相关方法,将文件传递功能进行了集成。
use async_std::task::spawn;
use clap::Parser;
use futures::prelude::*;
use libp2p::core::{Multiaddr, PeerId};
use libp2p::multiaddr::Protocol;
use libp2p_demo::network;
use std::error::Error;
use std::io::Write;
use std::path::PathBuf;#[async_std::main]
async fn main() -> Result<(), Box<dyn Error>> {env_logger::init();let opt = Opt::parse();// network::new 返回值是一个元组,包含三个部分:// network_client(网络客户端:用于在应用程序的任何位置与网络层进行交互。)、// network_events(网络事件流 :用于接收传入请求的事件流)// network_event_loop(网络任务驱动:用于驱动网络本身的任务)// network::new来自libp2p_demo::network模块,从源代码看其为Swarm::new的进一步封装let (mut network_client, mut network_events, network_event_loop) =network::new(opt.secret_key_seed).await?;// async-std 是一个用于异步编程的库,类似于 tokio// async-std::task::spawn()函数会在后台启动一个新的异步任务,允许多个任务同时执行,这样可以提高程序的并发性能。// Spawn the network task for it to run in the background.spawn(network_event_loop.run());// 启动网络监听 In case a listen address was provided use it, otherwise listen on any address.match opt.listen_address {Some(addr) => network_client.start_listening(addr)// 侦听给定地址上的输入连接请求.await.expect("Listening not to fail."),None => network_client.start_listening("/ip4/0.0.0.0/tcp/0".parse()?).await.expect("Listening not to fail."),};// 连接到指定的对等节点,如果命令行参数指定了对等节点的地址(peer),则根据地址中的信息构建对等节点的ID,并尝试通过dial方法连接到该节点。if let Some(addr) = opt.peer {let peer_id = match addr.iter().last() {Some(Protocol::P2p(hash)) => PeerId::from_multihash(hash).expect("Valid hash."),_ => return Err("Expect peer multiaddr to contain peer ID.".into()),};network_client.dial(peer_id, addr).await.expect("Dial to succeed");}// 处理命令行参数中的不同操作match opt.argument {// 如果提供了一个文件,即{ path, name }。CliArgument::Provide { path, name } => {// Advertise oneself as a provider of the file on the DHT.network_client.start_providing(name.clone()).await;//  network_client.start_providing将本地节点作为DHT上给定文件的提供者进行播发。loop {match network_events.next().await {// Reply with the content of the file on incoming requests.Some(network::Event::InboundRequest { request, channel }) => {if request == name {network_client.respond_file(std::fs::read(&path)?, channel).await;}}e => todo!("{:?}", e),}}}// 如果给出了一个名称,即{name}CliArgument::Get { name } => {// Locate all nodes providing the file.let providers = network_client.get_providers(name.clone()).await;if providers.is_empty() {return Err(format!("Could not find provider for file {}.", name).into());}// Request the content of the file from each node.let requests = providers.into_iter().map(|p| {let mut network_client = network_client.clone();let name = name.clone();async move { network_client.request_file(p, name).await }.boxed()});// Await the requests, ignore the remaining once a single one succeeds.let file_content = futures::future::select_ok(requests).await.map_err(|_| "None of the providers returned file.")?.0;std::io::stdout().write_all(&file_content)?;}}Ok(())
}#[derive(Parser, Debug)] // #[derive(Parser, Debug)]: 这是一个Rust的属性宏(attribute macro),用于自动为结构体实现解析器(parser)和调试输出(Debug trait)。Parser是由Clap库提供的,用于解析命令行参数
#[clap(name = "libp2p file sharing example")] // #[clap(name = "libp2p file sharing example")]: 这个属性指定了生成的命令行接口的名称为 "libp2p file sharing example"。
struct Opt {///  #[clap(long)] // #[clap(long)]: 这个属性指示Clap库将下面的字段作为长格式命令行参数处理。长格式参数通常由两个破折号(--)引导,例如 --secret-key-seed。/// Fixed value to generate deterministic peer ID.#[clap(long)]secret_key_seed: Option<u8>,#[clap(long)]peer: Option<Multiaddr>,#[clap(long)]listen_address: Option<Multiaddr>,#[clap(subcommand)] //  #[clap(subcommand)] 属性,表示它是一个子命令(subcommand)。CliArgument 可能是一个枚举类型,用于定义不同的子命令选项。argument: CliArgument,
}
// 有两个成员的枚举变量
#[derive(Debug, Parser)]
enum CliArgument {Provide {#[clap(long)]path: PathBuf,#[clap(long)]name: String,},Get {#[clap(long)]name: String,},
}

运行结果

发送端

  • cargo run --example 05-file-sharing -- --listen-address /ip4/127.0.0.1/tcp/40837 --secret-key-seed 1 provide --path ./test.exe --name testname
PS C:\Users\kingchuxing\Documents\learning-libp2p-main\rust> cargo run --example 05-file-sharing -- --listen-address /ip4/127.0.0.1/tcp/40837 --secret-key-seed 1 proet-key-seed 1 provide --path .\test.txt --name testnameCompiling libp2p_demo v0.1.0 (C:\Users\kingchuxing\Documents\learning-libp2p-main\rust)Finished `dev` profile [unoptimized + debuginfo] target(s) in 4.47sRunning `target\debug\examples\05-file-sharing.exe --listen-address /ip4/127.0.0.1/tcp/40837 --secret-key-seed 1 provide --path .\test.txt --name testname`
Local node is listening on "/ip4/127.0.0.1/tcp/40837/p2p/12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X"

接收端

  • 由于最后需要用std::io::stdout().write_all(&file_content)?;输出文件内容,所以采用了txt格式的文件进行测试
  • cargo run --example 05-file-sharing -- --peer /ip4/127.0.0.1/tcp/40837/p2p/12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X get --name testname
PS C:\Users\kingchuxing\Documents\learning-libp2p-main\rust> cargo run --example 05-file-sharing  -- --peer /ip4/127.0.0.1/tcp/40837/p2p/12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X    get   --name testnameFinished `dev` profile [unoptimized + debuginfo] target(s) in 0.32sRunning `target\debug\examples\05-file-sharing.exe --peer /ip4/127.0.0.1/tcp/40837/p2p/12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X get --name testname`
Local node is listening on "/ip4/192.168.3.12/tcp/62691/p2p/12D3KooWDDffKUnjVzsbMK5JHNQHsTE8FJNQDzS9tzKwSckGPe3f"
Local node is listening on "/ip4/127.0.0.1/tcp/62691/p2p/12D3KooWDDffKUnjVzsbMK5JHNQHsTE8FJNQDzS9tzKwSckGPe3f"
12345656867867867867867845634534523423453534564654645634 // test.txt文件的内容

参数解释

Usage: 05-file-sharing.exe [OPTIONS] <COMMAND>Commands:providegethelp     Print this message or the help of the given subcommand(s)Options:--secret-key-seed <SECRET_KEY_SEED>  Fixed value to generate deterministic peer ID //用于决定生成peer ID的固定值--peer <PEER>--listen-address <LISTEN_ADDRESS>-h, --help                               Print help
error: process didn't exit successfully: `target\debug\examples\05-file-sharing.exe` (exit code: 2)

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • C++友元
  • mysql5.6的安装步骤
  • PyCharm 安装
  • 【C++】类型擦除 + 工厂模式,告别 if-else
  • My sql 安装,环境搭建
  • 【C++PCL】点云处理误差RMSE值计算
  • Spring Boot与RSocket的集成
  • IDEA常用技巧荟萃:精通开发利器的艺术
  • 字符串中的注意事项
  • Postman深度解析:打造高效接口测试自动化流程
  • firewalld(6)自定义services、ipset
  • Spring 使用 Ehcache 技术指南
  • OFDM中采样频率与带宽的关系
  • 什么是设计模式以及常见的例子(如单例、工厂、观察者等)
  • IT高手修炼手册(3)程序员命令
  • (十五)java多线程之并发集合ArrayBlockingQueue
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • canvas 绘制双线技巧
  • Java 23种设计模式 之单例模式 7种实现方式
  • java小心机(3)| 浅析finalize()
  • magento2项目上线注意事项
  • REST架构的思考
  • 对话:中国为什么有前途/ 写给中国的经济学
  • 给Prometheus造假数据的方法
  • 技术:超级实用的电脑小技巧
  • 聊聊spring cloud的LoadBalancerAutoConfiguration
  • 微信小程序设置上一页数据
  • 原创:新手布局福音!微信小程序使用flex的一些基础样式属性(一)
  • media数据库操作,可以进行增删改查,实现回收站,隐私照片功能 SharedPreferences存储地址:
  • 《码出高效》学习笔记与书中错误记录
  • ​埃文科技受邀出席2024 “数据要素×”生态大会​
  • ​水经微图Web1.5.0版即将上线
  • ​无人机石油管道巡检方案新亮点:灵活准确又高效
  • ‌U盘闪一下就没了?‌如何有效恢复数据
  • ######## golang各章节终篇索引 ########
  • #DBA杂记1
  • (1)无线电失控保护(二)
  • (20050108)又读《平凡的世界》
  • (DenseNet)Densely Connected Convolutional Networks--Gao Huang
  • (Java入门)学生管理系统
  • (超简单)构建高可用网络应用:使用Nginx进行负载均衡与健康检查
  • (黑马点评)二、短信登录功能实现
  • (免费领源码)python+django+mysql线上兼职平台系统83320-计算机毕业设计项目选题推荐
  • (算法)Game
  • (转)jQuery 基础
  • (转)Linux整合apache和tomcat构建Web服务器
  • (转)负载均衡,回话保持,cookie
  • . NET自动找可写目录
  • .form文件_一篇文章学会文件上传
  • .NET Compact Framework 多线程环境下的UI异步刷新
  • .net dataexcel 脚本公式 函数源码
  • @ConditionalOnProperty注解使用说明
  • @JsonSerialize注解的使用
  • [.net]官方水晶报表的使用以演示下载
  • [12] 使用 CUDA 加速排序算法