项目名称:P2P文件共享神器


项目介绍:

该项目完成了一个基于本地局域网的P2P文件共享小工具。本项目分为客户端与服务端。以下是功能介绍:

  1. 能够进行搜索匹配局域网中运行此工具的在线主机;获取到局域网在线主机列表,并进行多线程主机配对;
  2. 能够获取指定主机所共享的文件信息列表(指定的共享目录下的文件信息);
  3. 能够对指定主机上的指定文件进行多线程分块下载来提高传输效。

使用到的库

本项目基于HTTPLIB库,以及使用了BOOST库中的文件系统与BOOST线程库还有BOOST库中的算法库;在获取局域网内IP地址是用的是


服务端功能接口

  1. 提供客户端的主机配对功能
  2. 提供客户端的文件列表获取功能
  3. 提供客户端的文件下载功能
#define SHARD_PATH "SHARD"
class P2PServer{private:// 实例化一个服务端Server _server;
private:// 主机配对static void GetHostPair(const Request& req,Response& rsp);// 文件列表信息static void GetFileList(const Request& req,Response& rsp);// 获取文件数据static void GetFileData(const Request& req,Response& rsp);// 分块响应数据static bool RangeParse(std::string &range_val, int64_t &start, \int64_t &len);
public:P2PServer(){if(!bf::exists(SHARD_PATH)){bf::create_directory(SHARD_PATH);}}bool Start(uint16_t port){_server.Get("/hostpair",GetHostPair);_server.Get("/list",GetFileList);_server.Get("/list/(.*)",GetFileData);_server.listen("0.0.0.0",port);}
};

客户端功能接口

  1. 提供能够发现匹配局域网附近主机功能
  2. 提供能够获取指定主机共享文件列表功能
  3. 提供能够下载指定主机下指定的共享文件功能
class P2PClient{private:uint16_t _srv_port;int _host_idx;std::vector<std::string> _online_list;std::vector<std::string> _file_list;
private:// 获取局域网内所有IP地址bool GetAllHost(std::vector<std::string> &list);// 获取局域网内所有IP地址线程入口函数void HostPair(std::string &i);// 获取在线主机列表bool GetOnlineHost(std::vector<std::string> &list);// 进行主机配对bool ShowOnlineHost();// 获取文件列表信息bool GetFileList();// 选择下载文件列表bool ShowFileList(std::string &name);// 分块请求下载线程入口函数void RangeDownLoad(std::string host, std::string name, int64_t start, int64_t end, int *res);// 获取文件大小int64_t GetFileSize(std::string &host, std::string &name);// 下载文件bool DownLoadFile(std::string &name);// 用户界面int DoFace(){std::cout << "0. 退出\n";std::cout << "1. 搜索附近主机\n";std::cout << "2. 显示在线主机\n";std::cout << "3. 显示文件列表\n";int choose = 0;std::cout << "please choose:";fflush(stdout);std::cin >> choose;return choose;}
public:P2PClient(uint16_t port):_srv_port(port){}bool Start();
};

接口熟悉:

1. 使用httplib库

#include "httplib.h"static void HelloWorld(const httplib::Request &req, httplib::Response &rsp) {    rsp.set_content("<html>hello world</html>", "text/html");return;
}int main() {    httplib::Server srv;    srv.set_base_dir("./www");    srv.Get("/", HelloWorld);    srv.listen("0.0.0.0", 9000); return 0;
}
// g++ -std=c++0x test.cpp -o test -lpthread -lboost_filesystem -lboost_system

服务端源代码:

#include<iostream>
#include<unistd.h>
#include<boost/filesystem.hpp>
#include<stdio.h>
#include "httplib.h"#define SHARD_PATH "SHARD"
#define LOG(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)using namespace httplib;
namespace bf = boost::filesystem;class P2PServer
{private:Server _server;private:static void GetHostPair(const Request& req,Response& rsp){rsp.status =200;return;}static void GetFileList(const Request& req,Response& rsp){bf::directory_iterator it_begin(SHARD_PATH);bf::directory_iterator it_end;std::stringstream body;// body<<"<html><body>";for(;it_begin!=it_end;it_begin++){if(bf::is_directory(it_begin->status())){continue;}std::string name = it_begin->path().filename().string();rsp.body+=name+"\n";// body << "<h4><a href='/list/"<< name <<"'>";// body << name;// body <<"</a></h4>";//rsp.body+=name;}// body<<"</body></html>";// rsp.body = body.str();rsp.set_header("Content-Type","text/html");//渲染rsp.status = 200;}static void GetFileData(const Request& req,Response& rsp){//a.txt->Dowanload/a.txtbf::path path(req.path); //生成一个path对象std::stringstream name;name<< SHARD_PATH << "/" << path.filename().string();if(!bf::exists(name.str())){rsp.status = 404;return;}if(bf::is_directory(name.str())){rsp.status = 403;return;}int64_t fsize = bf::file_size(name.str());if(req.method == "HEAD"){rsp.status = 200;std::string len = std::to_string(fsize);rsp.set_header("Content-Length", len.c_str());return;}else{if(!req.has_header("Range")){rsp.status = 400;return;}std::string range_val;range_val = req.get_header_value("Range");int64_t start, rlen;bool ret = RangeParse(range_val, start, rlen);if(ret == false){rsp.status = 400;return;}std::cerr << "body.resize: " << rlen << "\n";rsp.body.resize(rlen);std::ifstream file(name.str(),std::ios::binary);if(!file.is_open()){std::cerr<<"open file"<<name.str()<<"failed\n";rsp.status = 404;return;}file.seekg(start, std::ios::beg);file.read(&rsp.body[0],rlen); //写到body里了if(!file.good()){std::cerr<<"read file"<<name.str()<<"body error\n";rsp.status = 500;return;}file.close();rsp.status = 206;rsp.set_header("Content-Type","application/octet-stream");//二进制流std::cerr << "file range: " << range_val;std::cerr << "download success\n";}}static bool RangeParse(std::string &range_val, int64_t &start, \int64_t &len){size_t pos1 = range_val.find("=");size_t pos2 = range_val.find("-");if(pos1 == std::string::npos ||pos2 == std::string::npos){std::cerr << "range " << range_val << " format error\n";return false;}int64_t end;std::string rstart;std::string rend;rstart = range_val.substr(pos1 + 1, pos2 - pos1 - 1);rend = range_val.substr(pos2 + 1);std::stringstream tmp;tmp << rstart;tmp >> start;tmp.clear();tmp << rend;tmp >> end;len = end - start + 1;return true;}public:P2PServer(){if(!bf::exists(SHARD_PATH)){bf::create_directory(SHARD_PATH);}}bool Start(uint16_t port){_server.Get("/hostpair",GetHostPair);_server.Get("/list",GetFileList);_server.Get("/list/(.*)",GetFileData);_server.listen("0.0.0.0",port);}
};int main()
{P2PServer srv;srv.Start(9000);return 0;
}

客户端:

#include <iostream>
#include <fcntl.h>
#include <string>
#include <unistd.h>
#include <vector>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/thread.hpp>
#include <fstream>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "httplib.h"
#include <thread>#define RANGE_SIZE (1024*1024*10)   // 10M
using namespace httplib;
namespace bf = boost::filesystem;class P2PClient{private:uint16_t _srv_port;int _host_idx;std::vector<std::string> _online_list;std::vector<std::string> _file_list;
private:bool GetAllHost(std::vector<std::string> &list){struct sockaddr_in *ip = NULL;struct sockaddr_in *mask = NULL;struct ifaddrs *addrs = NULL;getifaddrs(&addrs);for(; addrs != NULL; addrs = addrs->ifa_next){ip = (struct sockaddr_in*)addrs->ifa_addr;mask = (struct sockaddr_in*)addrs->ifa_netmask;if(ip->sin_family != AF_INET){continue;}if(ip->sin_addr.s_addr == inet_addr("127.0.0.1")){continue;}uint32_t net, host;net = ntohl(ip->sin_addr.s_addr & mask->sin_addr.s_addr);host = ntohl(~mask->sin_addr.s_addr);for(int i = 2; i < host-1; i++){struct in_addr ip;ip.s_addr = htonl(net+i);list.push_back(inet_ntoa(ip));}}freeifaddrs(addrs);return true;}void HostPair(std::string &i){Client client(i.c_str(), _srv_port);auto req = client.Get("/hostpair");if(req && req->status == 200){std::cerr << "host " << i << " pair success\n";_online_list.push_back(i);}std::cerr << "host " << i << " pair failed\n";return;}bool GetOnlineHost(std::vector<std::string> &list){_online_list.clear();std::vector<std::thread> thr_list(list.size());for(int i = 0; i < list.size(); i++){std::thread thr(&P2PClient::HostPair, this, std::ref(list[i]));thr_list[i] = std::move(thr);}for(int i = 0; i < thr_list.size(); i++){thr_list[i].join();}return true;}bool ShowOnlineHost(){for(int i = 0; i < _online_list.size(); i++){std::cout << i << ". " << _online_list[i] << "\n";}std::cout << "please choose:";fflush(stdout);std::cin >> _host_idx;if(_host_idx < 0 || _host_idx > _online_list.size()){std::cerr << "choose error\n";return false;}return true;}bool GetFileList(){Client client(_online_list[_host_idx].c_str(), _srv_port);auto req = client.Get("/list");if(req && req->status == 200){//std::vector<std::string> list;boost::split(_file_list, req->body, boost::is_any_of("\n"));}return true;}bool ShowFileList(std::string &name){for(int i = 0; i < _file_list.size(); i++){std::cout << i << ". " << _file_list[i] << "\n";}std::cout << "please choose:";fflush(stdout);int file_idx;std::cin >> file_idx;if(file_idx < 0 || file_idx > _file_list.size()){std::cerr << "choose error\n";return false;}name = _file_list[file_idx];return true;}void RangeDownLoad(std::string host, std::string name, int64_t start, int64_t end, int *res){std::string uri = "/list/" + name;std::string realpath = "Download/" + name;std::stringstream range_val;range_val << "bytes=" << start << "-" << end;std::cerr << "download range: " << range_val.str() << "\n"; *res = 0;Client client(host.c_str(), _srv_port);Headers header;header.insert(std::make_pair("Range", range_val.str().c_str()));auto req = client.Get(uri.c_str(), header);if(req && req->status == 206){int fd = open(realpath.c_str(), O_CREAT | O_WRONLY, 0664);if(fd < 0){std::cerr << "file " << realpath << " open error\n";return;}lseek(fd, start, SEEK_SET);int ret = write(fd, &req->body[0], req->body.size());if(ret < 0){std::cerr << "file " << realpath << "write error\n";close(fd);return;}close(fd);*res = 1;std::cerr << "file " << realpath << " download range:";std::cerr << range_val.str() << " success\n";}return;}int64_t GetFileSize(std::string &host, std::string &name){int64_t fsize = -1;std::string path = "/list/" + name;Client client(host.c_str(), _srv_port);auto req = client.Head(path.c_str());if(req && req->status == 200){if(!req->has_header("Content-Length")){return -1;}std::string len = req->get_header_value("Content-Length");std::stringstream tmp;tmp << len;tmp >> fsize;}return fsize;}bool DownLoadFile(std::string &name){// GET /list/filenamestd::string host = _online_list[_host_idx];int64_t fsize = GetFileSize(host, name);    if(fsize < 0){std::cerr << "download file " << name << "failed\n";return false;}int count = fsize / RANGE_SIZE;std::cout << "range count: " << count << "\n";std::vector<boost::thread> thr_list(count + 1);std::vector<int> res_list(count + 1);for(int64_t i = 0; i <= count; i++){int64_t start, end, len;start = i * RANGE_SIZE;end = (i + 1) * RANGE_SIZE - 1;if(i == count){if(fsize % RANGE_SIZE == 0){break;}end = fsize - 1;}std::cerr << "range: " << start << "-" << end <<"\n";len = end - start + 1;int *res = &res_list[i];boost::thread thr(&P2PClient::RangeDownLoad, this, host, name, start, end, res);thr_list[i] = std::move(thr);}bool ret = true;for(int i = 0; i <= count; i++){if(i == count && fsize % RANGE_SIZE == 0){break;}thr_list[i].join();if(res_list[i] == 0){ret = false;}}if(ret == true){std::cerr << "download file " << name << " success\n";}else{std::cerr << "download file " << name << " failed\n";return false;}return true;}int DoFace(){std::cout << "0. 退出\n";std::cout << "1. 搜索附近主机\n";std::cout << "2. 显示在线主机\n";std::cout << "3. 显示文件列表\n";int choose = 0;std::cout << "please choose:";fflush(stdout);std::cin >> choose;return choose;}
public:P2PClient(uint16_t port):_srv_port(port){}bool Start(){while(1){int choose = DoFace();std::string filename;std::vector<std::string> list;switch(choose){case 1:GetAllHost(list);GetOnlineHost(list);break;case 2:if(ShowOnlineHost() == false){break;}GetFileList();break;case 3:if(ShowFileList(filename) == false){break;}DownLoadFile(filename);break;case 0:exit(0);default:break;}}}};int main(){P2PClient cli(9000);cli.Start();return 0;
}

makefile:

all:server client
client:client.cppg++ -std=c++0x $^ -o $@ -lpthread -lboost_filesystem -lboost_system -lboost_thread
server:server.cppg++ -std=c++0x $^ -o $@ -lpthread -lboost_filesystem -lboost_system

小项目---基于局域网的P2P文件共享工具相关推荐

  1. 基于UDP的P2P聊天工具 0.3——消息队列和重传

    基于UDP的P2P聊天工具 0.3--消息队列和重传 简介: 1)这是一个Windows的P2P聊天工具: 2)相比0.2,它多了定时重传的机制: 3)对局域网来说有些鸡肋,就当是为跨局域网做准备吧: ...

  2. 基于UDP的P2P聊天工具——0.2

    基于UDP的P2P聊天工具 0.2 简介: 1)这也是一个windows的P2P聊天工具: 2)它修复了0.1版的一个bug: 3)它为0.3版做了一点准备: 相关内容: 1)如果对端端口未开启服务, ...

  3. [carla入门教程]-6 小项目:基于carla-ros-bridge构建一个小型比赛赛道

    本专栏教程将记录从安装carla到调用carla的pythonAPI进行车辆操控并采集数据的全流程,带领大家从安装carla开始,到最终能够熟练使用carla仿真环境进行传感器数据采集和车辆控制. 第 ...

  4. 树莓派练手小项目---基于树莓派构建天气查询系统,实现内容的网页自动化检索功能

    目录 一.写在前面 二.基于树莓派构建天气查询系统 三.基于树莓派实现网页内容的自动化检索 四.有关于树莓派的其他小提醒,小技巧 Author:qyan.li Date:2022.6.19 Topic ...

  5. Java初学练手小项目---基于awt库,swing库以及MySQL数据库制作简易电影管理系统(一)

    前言 本人是个小小白,初学Java语言,想与一众身为程序猿的各位分享一下自己的知识和想法,达到共同学习的目的,所以想通过写博客的方式分享自己的心得体会,这也是本人第一次写博客,希望能够帮助同样在学习的 ...

  6. 庆祝一下,基于JXTA的P2P文件共享传输文件测试成功。

    jxta.org上也有一个资源共享的项目,jxta-cm,但是这个项目作的不够好. 我重新设计了传输协议,参考了BT的传输协议. 存储本地信息,不像jxta-cm那样简单,序列化一个本地磁盘文件,而是 ...

  7. MTCNN移植java_android小项目----基于mnn的mtcnn人脸检测

    阿里巴巴MNN框架 https://github.com/alibaba/MNN 项目代码 https://github.com/Danicaai/android-mnn 一. 简介 Android ...

  8. Qt网络编程小项目-基于Tcp协议的文件传输项目

    目录 项目描述 Qt下Tcp服务器端和客户端流程: 具体流程: 客户端: 服务器端: 源码: 服务器端: 服务器头文件: 服务器源文件: 服务器端ui 客户端: 客户端头文件: 客户端源文件: 客户端 ...

  9. Java初学小项目--基于awt库,swing库的可视化电影管理系统(三)

    前言 这是电影管理系统项目的第三篇博客,也是该程序最后一篇博客,前面两篇博客已经介绍了管理系统的可视化实现,看了前面博客的朋友对于各个功能可视化的实现应该都可以完成了,最后一步就是将我们要执行的指令传 ...

最新文章

  1. FileReader类型之文字读取
  2. 工作三年的一点感想(展望篇)
  3. 悲观锁定时如何避免可怕的死锁-以及Java 8的一些用法!
  4. 图结构练习——判断给定图是否存在合法拓扑序列
  5. python语言只采用解释一种翻译方式对吗_python与脚本语言
  6. 解决办法:apt: 未找到命令
  7. IOT | 物联网入门
  8. NepCTF2022
  9. 过山车css动画,three.js 124版本实现彩虹过山车动画
  10. 统计学三大相关性系数:pearson,spearman,kendall
  11. 在windows 10下编译可在windows xp下使用的 opencv 3.2
  12. Redis的底层数据结构----快速列表_quicklist
  13. 图像配准方面的算法总结
  14. 自举开关为啥用NMOS管,不用PMOS管
  15. 和12岁小同志搞创客开发:如何驱动红外遥控器?
  16. 在MAC中怎么把窗口快速移到另一个显示器
  17. l计算机中级zm,蘑菇爱搞机 篇一百四十:老将的最后一次升级了、770ZM更换海盗船2133mHz DDR3L内存...
  18. 四级英语黄金词组及常用15个句型
  19. 入局先进空中交通,Overair推出全电动垂直起降飞机
  20. pip安装torch错误ERROR: Could not find a version that satisfies the requirement torch及解决办法

热门文章

  1. Mac安装CAJViewer
  2. python教程二十五 标准库概览
  3. 了解内网、外网、宽带、带宽、流量、网速
  4. 电动助力转向EPS(二)——理论公式推导及simulink模型
  5. 珠海中级Java招聘 薪资16-20k
  6. layout-v17 导致资源 替换不全,替换不成功
  7. 盐城师范计算机二级成绩,盐城师范学院教务处
  8. 激情绿茵,助力2022卡塔尔世界杯——基于改进的YOLO模型玩转足球检测分析系统
  9. Accelerator更改默认使用的GPU卡号
  10. python有道云笔记_一键导出「有道云笔记」所有笔记