一、实验目的
- 学习p2p知识,并搭建一个局域网p2p下载器
- 使用p2p下载器进行文件的传输
二、实验环境
- IDEA【p2p_bootstrap,p2p_node】
- postman
三、实验步骤
1. 拉库
①git clone https://gitee.com/daitoulin/p2p_bootstrap.git
②git clone https://gitee.com/daitoulin/p2p_node.git
2. 具体操作
1)path类
java.nio.file.Path类是Java7引入的一个新类,用于表示文件系统的路径。提供了对文件路径的高级抽象,使得处理文件路径变得更加简单和一致。
平台无关性:Windows用
\,Linux/unix使用/提供了一系列静态工厂方法和实例方法,用来创建和操作路径。
path类和filesystem紧密集成,可以轻松获取文件系统的相关信息。
在p2p_node文件夹下
src/main/java/com.example.p2pshare.cotroller/下创建PathExample类,实践代码理解java.nio.file.Path类的使用,常见的一些方法的含义。这里需要注意一下resolvedpath=path.resolve("subdir/newfile.txt")如果这个subdir放在距离很远的文件夹会如何结果。
1 | package com.example.p2pshare.cotroller; |
运行结果如下:

2)file类
java.io.File类用于表示文件系统中的文件和目录,一组方法来创建、删除、重命名文件或目录,以及获取文件的各种属性,如文件大小、最后修改时间。File类只能操作文件或文件夹本身,不能读写文件里面的数据。
1 | package com.example.p2pshare.cotroller; |
运行结果如下:

3)InputStream和OutPutStream流简介
处理字节流的基本类。分别用于读取写入字节数据。
InputStream是一个抽象类,用于从源读取字节数据。所有的字节输入流都继承自InputStream。其常见的子类有:
FileInputStream从文件系统中的文件读取字节。从文件系统中的一个文件读取字节,打开一个从文件系统中的指定文件到应用程序的输入字节流。
FileOutputStream用于将数据写入文件系统中的文件。它创建一个向文件系统中指定文件提供输出的文件输出流。
ByteArrayInputStream从字节数组读取字节
ObjectInputStream用于反序列化对象
BUfferedInputStream为其他输入流添加缓冲功能,提高读取效率。
PipedInputStream用于线程间的通信,与PipedOutputStream配合使用。
OutputStream同样是一个抽象类,向目的地写入字节数据。其子类与InputStream类似。
1 | package com.example.p2pshare.cotroller; |
这里在main函数调用copyFileToFolder函数的时候添加了捕获异常的处理,否则IDEA会不让进行编译。
当目标文件夹不存在时:

当创建完毕:

会发现lee.txt被复制到了目标文件夹test2中:

4)使用springboot框架实现P2P节点的IP发现
拉取引导节点:git clone https://gitee.com/daitoulin/p2p_bootstrap.git
修改配置文件application.properties
1 | #引导节点IP:点开terminal输入ipconfig查看本地WLAN的IP地址 |
edit configurations:

run application

对等节点:
同样修改配置文件application.properties
1 | server.port=8888 |
run application【同上】出现Bootstrapped? true和引导节点取得连接

至此,完成了P2P下载器的节点发现功能。
5)使用springboot框架完成两个节点内的文件传输
①先启动引导节点
②启动对等节点
③postman的使用:指定IP,端口(p2p_node节点配置文件中service port 8888),指定接口,参数 进行文件的传输【post,get,request,body:form-data,raw-json】
6)常见接口
@RequestParam:将参数跟随在url的问号后面@RequestMapping可以支持get及post传参,将@RequestMapping改为@PostMapping然后使用get传参会发现失败。1
2
3
4
5
6
7
8
9
public ResponseEntity<JSONResult>testParam(String username){
JSONResult json=JSONResult.getInstance();
json.setCode("200");
json.setMsg("用户名为:"+username);
json.setContent("");
return new ResonseEntity<JSONResult>(json,HttpStatus.OK);
}![image-20240924222212001]()
修改之后,GET传参失败,证实了上述说明:
![image-20240924222501455]()
@RequestBody:将参数转为json放在请求体中@PathVariable:/test/{username},绑定最后一个斜杆后面的字符串1
2
3
4
5
6
7
8
9
public ResponseEntity<JSONResult> testPathVariable( String username){
JSONResult json = JSONResult.getInstance();
json.setCode("200");
json.setMsg("用户名为:" + username);
json.setContent("");
return new ResponseEntity<JSONResult>(json, HttpStatus.OK);
}![image-20240924223720919]()
/uploadFile:参数multipartFile选择file- 不加任何注释的:将自动转为Java实体类,一般前端以form-data形式传递
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public ResponseEntity<JSONResult> testUpload(MultipartFile multipartFile) throws IOException {
JSONResult json = JSONResult.getInstance();
String fileName = multipartFile.getOriginalFilename();
Path targetLocation = Paths.get(shareFilePath, fileName);
// 保存文件到指定位置
multipartFile.transferTo(targetLocation);
json.setCode("200");
json.setMsg("上传成功");
json.setContent("");
return new ResponseEntity<JSONResult>(json, HttpStatus.OK);
}在POSTMAN中使用uploadFile接口上传文件成功:参数multipartFile选择file,添加要上传的文件。
![image-20240924225659175]()
在HTML页面中查看确认上传成功:
![image-20240924225727420]()
![image-20240924225814855]()
selectIp:查询IP![image-20240926230749038]()
![image-20240924230352265]()
queryDocument查询文件,F12查看如下:![image-20240924230547313]()
![image-20240924231053189]()
/findDocument:![image-20240926232515380]()
/downloadFile以JSON形式上传ip,fileName下载文件失败了(将前端传输的文件名进行拼接,对指定的ip进行请求,收到返回的byte数组,存入本地指定目录)注意:下载的文件不能为空![image-20240924234930913]()
后面发现是配置文件中sharesfiles路径后面少了一个斜杠【表示共享文件夹,少了斜杠之后变成一个文件的路径了,故无法下载到文件】
![image-20240926000142444]()
![image-20240926000054087]()
/download/{fileName}:将指定的文件读取转为byte数组并返回![image-20240926233431075]()
四、实验结果与讨论
引导节点、对等节点启动成功
![image-20240927000052117]()
P2P下载器实现文件的上传下载
![image-20240927000248147]()
五、总结
P2P下载器是一类用于获取大文件或数据的应用程序,利用点对点技术(P2P)实现高效的下载过程。与传统的中心化下载方式不同,P2P下载器允许用户从多个源同时下载文件,提高了下载速度和资源利用率。
Spring Boot 应用程序通常遵循分层架构设计原则,其中最常见的是三层架构:Controller、Service 和 Repository。每一层都有其特定的责任。①controller层:在Spring MVC中,控制器通常由带有
@RestController或@Controller注解的类实现。②service层:通常由带有@Service注解的类实现。③Repository层:通常由带有@Repository注解的类实现,并且经常使用Spring Data JPA或其他ORM框架来简化数据库操作。springboot框架实现 本地文件的传输、节点的IP发现、节点间的文件传输。
使用Spring Boot可以快速搭建P2P网络的服务端,包括节点管理、资源分配、用户认证等功能。
通过接口进行功能的访问,每个接口有相对应的参数。
downloadFile接口是通过读取字节流下载,其文件要求不为空否则失败。引导节点中sharefiles的路径
share.file.path=D:/BlockChain/IdeaProjects/p2p_node/sharefiles/注意这是一个文件夹的路径,最后的一个斜杠如果漏了会变成文件路径,文件下载会失败。同时要注意到斜杆的方向。
















