学习P2P知识,并搭建一个局域网p2p下载器

学习P2P知识,并搭建一个局域网p2p下载器

一、实验目的

学习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放在距离很远的文件夹会如何结果。

12345678910111213141516171819202122232425262728293031323334353637package com.example.p2pshare.cotroller;import org.springframework.http.codec.multipart.PartHttpMessageWriter;import java.nio.file.Path;import java.nio.file.Paths;public class PathExample { public static void main(String[] args) { //创建路径 Path path=Paths.get("D:/BlockChain/IdeaProjects/testfile/Lee.txt"); //获取父路径 Path parent=path.getParent(); System.out.println("Parent:"+parent); //获取文件名 Path fileName=path.getFileName(); System.out.println("File name:"+fileName); //解析相对路径 Path resolvePath=path.resolve("E:/newnewLee.txt"); System.out.println("Resloved path:"+resolvePath); //规范化路径 Path normalizedPath=path.normalize(); System.out.println("Normalized path:"+normalizedPath); //转换为绝对路径 Path absolutePath=path.toAbsolutePath(); System.out.println("Absolute path:"+absolutePath); //转换为file对象 java.io.File file=path.toFile(); System.out.println("File object:"+file); }}

运行结果如下:

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

123456789101112131415161718192021222324252627282930313233343536373839404142package com.example.p2pshare.cotroller;import java.io.File;import java.io.IOException;public class FileExample { public static void main(String[] args) { //创建file对象 File file=new File("D:/BlockChain/IdeaProjects/testfile/Lee.txt"); //输出文件信息 System.out.println("File exists:"+file.exists()); System.out.println("Is directory:"+file.isDirectory()); System.out.println("Is file:"+file.isFile()); System.out.println("Path:"+file.getPath()); System.out.println("Name:"+file.getName()); System.out.println("Parent:"+file.getParent()); System.out.println("Absolute path:"+file.getAbsolutePath()); System.out.println("Length:"+file.length()); System.out.println("Last modified:"+file.lastModified()); try { //创建文件或目录 File newFile=new File("E:/Likt/test/lee3.txt"); boolean created=newFile.createNewFile(); System.out.println("Created new file:"+created); File newDir=new File("E:/Likt/test/newdir/"); boolean dirCreated=newDir.mkdir(); System.out.println("Created new directory:"+dirCreated); //列出目录中的文件 File dir=new File("E:/Likt/test/"); String[] files=dir.list(); for (String fileName:files){ System.out.println("File in directory:"+fileName); } }catch (IOException e){ System.err.println("An IOException occurred:"+e.getMessage()); } }}

运行结果如下:

3)InputStream和OutPutStream流简介

处理字节流的基本类。分别用于读取写入字节数据。

InputStream是一个抽象类,用于从源读取字节数据。所有的字节输入流都继承自InputStream。其常见的子类有:

FileInputStream从文件系统中的文件读取字节。从文件系统中的一个文件读取字节,打开一个从文件系统中的指定文件到应用程序的输入字节流。

FileOutputStream用于将数据写入文件系统中的文件。它创建一个向文件系统中指定文件提供输出的文件输出流。

ByteArrayInputStream从字节数组读取字节

ObjectInputStream用于反序列化对象

BUfferedInputStream为其他输入流添加缓冲功能,提高读取效率。

PipedInputStream用于线程间的通信,与PipedOutputStream配合使用。

OutputStream同样是一个抽象类,向目的地写入字节数据。其子类与InputStream类似。

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950package com.example.p2pshare.cotroller;import org.springframework.web.bind.annotation.RestController;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.nio.file.Files;import java.nio.file.Path;import java.nio.file.Paths;@RestControllerpublic class TestController { public static void main(String[] args) { String sourceFilePath = "D:\\BlockChain\\IdeaProjects\\testfile\\Lee.txt"; String destinationFolderPath = "D:\\BlockChain\\IdeaProjects\\testfile\\test2\\"; Path sourcePath = Paths.get(sourceFilePath);//源文件路径 Path destFolderPath = Paths.get(destinationFolderPath);//目标文件夹路径 Path destFilePath = destFolderPath.resolve(sourcePath.getFileName());//目标文件的地址;这里还是相对路径的问题 try { copyFileToFolder(sourcePath, destFilePath); }catch (IOException e){ System.out.println("这里异常了一下"); e.printStackTrace(); } } public static void copyFileToFolder(Path sourcePath,Path destFilePath) throws IOException{ //检查源文件是否存在 if(!Files.exists(sourcePath)){ throw new IOException("源文件不存在:"+sourcePath); } if(!Files.isDirectory(destFilePath.getParent())){ throw new IOException("目标文件不存在:"+destFilePath.getParent()); } try(FileInputStream fis =new FileInputStream(sourcePath.toFile()); FileOutputStream fos=new FileOutputStream(destFilePath.toFile()) ){ //创建一个字节数组来存储文件内容 byte[] buffer= new byte[1024];//使用较大的缓冲区 int bytesRead; //循环读取文件内容直到读完 while ((bytesRead=fis.read(buffer))!=-1){ //写入到目标文件 fos.write(buffer,0,bytesRead); } } }}

这里在main函数调用copyFileToFolder函数的时候添加了捕获异常的处理,否则IDEA会不让进行编译。

当目标文件夹不存在时:

当创建完毕:

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

4)使用springboot框架实现P2P节点的IP发现拉取引导节点:git clone https://gitee.com/daitoulin/p2p_bootstrap.git

修改配置文件application.properties

1234#引导节点IP:点开terminal输入ipconfig查看本地WLAN的IP地址bootstrap.ip= 10.39.203.64#引导节点端口bootstrap.port=8883

edit configurations:

run application

对等节点:

同样修改配置文件application.properties

12345678910server.port=8888#引导节点IP:点开terminal输入ipconfig查看本地WLAN的IP地址bootstrap.ip= 10.39.203.64#引导节点端口bootstrap.port=8883node.ip= 10.39.203.64node.port = 8887spring.servlet.multipart.max-request-size=200MBspring.servlet.multipart.max-file-size=200MBshare.file.path=D:/BlockChain/IdeaProjects/p2p_node/sharefiles

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传参会发现失败。

123456789@RequestMapping("/testParam")public ResponseEntitytestParam(@RequestParam("username")String username){ JSONResult json=JSONResult.getInstance(); json.setCode("200"); json.setMsg("用户名为:"+username); json.setContent(""); return new ResonseEntity(json,HttpStatus.OK);}

修改之后,GET传参失败,证实了上述说明:

@RequestBody:将参数转为json放在请求体中

@PathVariable:/test/{username},绑定最后一个斜杆后面的字符串

123456789@RequestMapping("/testPathVariable/{username}")public ResponseEntity testPathVariable(@PathVariable("username") String username){ JSONResult json = JSONResult.getInstance(); json.setCode("200"); json.setMsg("用户名为:" + username); json.setContent(""); return new ResponseEntity(json, HttpStatus.OK);}

/uploadFile:参数multipartFile选择file

不加任何注释的:将自动转为Java实体类,一般前端以form-data形式传递

1234567891011121314@PostMapping("/uploadFile")public ResponseEntity 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(json, HttpStatus.OK);}

在POSTMAN中使用uploadFile接口上传文件成功:参数multipartFile选择file,添加要上传的文件。

在HTML页面中查看确认上传成功:

selectIp:查询IP

queryDocument查询文件,F12查看如下:

/findDocument:

/downloadFile以JSON形式上传ip,fileName下载文件失败了(将前端传输的文件名进行拼接,对指定的ip进行请求,收到返回的byte数组,存入本地指定目录)注意:下载的文件不能为空

后面发现是配置文件中sharesfiles路径后面少了一个斜杠【表示共享文件夹,少了斜杠之后变成一个文件的路径了,故无法下载到文件】

/download/{fileName}:将指定的文件读取转为byte数组并返回

四、实验结果与讨论

引导节点、对等节点启动成功

P2P下载器实现文件的上传下载

五、总结

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/注意这是一个文件夹的路径,最后的一个斜杠如果漏了会变成文件路径,文件下载会失败。同时要注意到斜杆的方向。

相关创意

配朵朵 - 配音就找配朵朵
365bet网上足球

配朵朵 - 配音就找配朵朵

📅 07-23 👁️ 1111
32寸电视功率一般多少瓦-32寸电视多大功率
365bet网上足球

32寸电视功率一般多少瓦-32寸电视多大功率

📅 01-07 👁️ 1205