项目:信息共享工具

news/2024/10/22 16:24:58/

一.项目介绍:

该项目是一个局域网中进行附近文件共享下载的工具;实现能够进行搜索匹配局域网中运行工具的主机获取到局域网中在线主机列表,然后获取指定主机所共享的文件列表信息,并且对指定主机的指定文件进行多进程分块下载提高传输效率;
实质:搜索到局域网中的在线用户,获取到在线用户的列表后查看指定用户的共享文件列表,然后对感兴趣的文件进行选择下载;

二.整体的项目框架:

在这里插入图片描述
在这里插入图片描述

服务器端设计:
设计实现http服务端程序,能够提供浏览器客户端进行文件的下载,获取文件列表功能

客户端设计:
实现基于服务器HTTP的分块传输功能实现多进程文件分块下载功能的下载器,通过分块传输提高传输效率

三.实现流程:

  1. 发现局域网附近共享用户
  2. 列出附近用户列表,并选择想要查看的用户主机
  3. 获取指定用户的文件列表,并选择想要下载的文件
  4. 获取文件的头信息,主要获取文件长度
  5. 对获取到的长度进行下载分块区域划分
  6. 创建多进程进行分块下载文

四.主要的接口设计:

1.服务端功能接口:
  • 提供客户端的主机配对功能;
  • 提供客户端的文件列表获取功能;
  • 提供客户端的文件下载功能;

/* 客户端配对请求        请求: GET /hostpair HTTP/1.1              /hostpair        响应: HTTP/1.1 200 OK    客户端文件列表获取请求        请求: GET /list/ HTTP/1.1                 /(list/){0,1}        响应:              HTTP/1.1 200 OK              Content-Length: len                            filename1\n              filename2\n              ...    客户端文件分块下载请求        请求:            GET /list/filename HTTP/1.1           /list/(.*)            Range: byte=range_start-range_end        响应:            HTTP/1.1 200 OK            Content-Length: range_size                       range_data 
*/ #define SHARED_DIR  "shared" 
class P2PServer {    
private:        httplib::Server srv;    public:        /*附近主机配对请求处理*/        static void PairHandler(const Request& req, Response& res);        /*文件列表请求处理*/       static void ListHandler(const Request& req, Response& res);        /*文件下载请求处理*/        static void DownloadHandler(const Request& req, Response& res); };
2.客户端功能接口:
  • 提供能够发现匹配局域网附近主机的功能;
  • 提供能够获取指定主机共享文件列表功能;
  • 提供能够下载指定主机下指定的共享文件功能;
  • 能够进行客户端的功能显示;

#define DOWNLOAD_DIR    "download" 
#define RANGE_SIZE      (10 << 20) 
class P2pClient {    
private:        std::vector<std::string> _host_list; std::vector<std::string> _file_list;    
private:        bool GetHostList(std::vector<std::string> &list);        int64_t GetFileSize(int file_id);    public:        int  SelectShow();                      //用户选择显示        bool PairNearbyHost();                  //附近主机匹配        bool ShowNearByHost();                  //显示附近主机        bool GetShareList(int host_id);         //获取指定主机的共享文件列表        bool ShowShareList();                   //显示指定主机的共享文件列表        bool DownLoadFile(int file_id);         //下载指定主机的共享文件 };
3.其他接口的使用:

httplib基本使用:

/*test.cpp*/ 
#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); 
} /*g++ -std=c++0x test.cpp -o test -lpthread -lboost_filesystem -lboost_system*/struct ifaddrs *addrs = NULL; 
int getifaddrs(struct ifaddrs **ifap);                  /*获取本机网卡信息*/    
//返回值:0-成功    -1-失败 void freeifaddrs(struct ifaddrs *ifa);                  /*释放网卡信息存储资源*/ struct ifaddrs {    struct ifaddrs *ifa_next;       /* 链表指针,指向下一个网卡信息 */    char *ifa_name;                 /* 网卡名称*/    unsigned int ifa_flags;         /* Flags as from SIOCGIFFLAGS ioctl.  */    struct sockaddr *ifa_addr;      /* 地址结构*/    struct sockaddr *ifa_netmask;   /* 子网掩码*/    union    {        /* At most one of the following two is valid.  If the IFF_BROADCAST       bit is set in `ifa_flags', then `ifa_broadaddr' is valid.  If the       IFF_POINTOPOINT bit is set, then `ifa_dstaddr' is valid.       It is never the case that both these bits are set at once.  */        struct sockaddr *ifu_broadaddr;     /* Broadcast address of this interface. */             struct sockaddr *ifu_dstaddr;       /* Point-to-point destination address.  */ }ifa_ifu;    # ifndef ifa_broadaddr    
# define ifa_broadaddr ifa_ifu.ifu_broadaddr    
# endif    
# ifndef ifa_dstaddr    
# define ifa_dstaddr   ifa_ifu.ifu_dstaddr    
# endif    
void *ifa_data;       /* Address-specific data (may be unused).  */ 
}; 

五.代码实现原理:

关于服务端基本功能的实现:
Server.hpp

//实现服务端的基本功能:                                                                                                        
//1.搭建http服务器;
//2.实现主机配对的功能,主要用于局域网的主机搜索配对功能;
//3.实现文件列表的获取,主要是向客户端提供一个文件列表,让用户来选择;
//4.响应文件的数据下载功能;
#ifndef __M_SRV_H__
#define __M_SRV_H__
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <boost/filesystem.hpp>
#include "httplib.h" using namespace httplib;
namespace bf=boost::filesystem;#define SHARED_PATH "Download"#define LOG(fmt,...)  fprintf(stderr,fmt,__VA_ARGS__) 
class P2PServer{
private:Server _server;
private:                              static void GetHostPair(const Request &req,Response &rsp){    //主机配对rsp.status=200;}static void GetFileList(const Request &req,Response &rsp){    //获取文件列表bf::directory_iterator item_begin(SHARED_PATH);bf::directory_iterator item_end;std::stringstream body;for(;item_begin!=item_end;++item_begin){if(bf::is_directory(item_begin->status())){   //如果是一个目录就跳过;continue;}bf::path path=item_begin->path();std::string name = path.filename().string();rsp.body += name + "\n";                                                                                                  }rsp.set_header("Content-Type","text/html");rsp.status=200;}static void GetFileData(const Request &req,Response &rsp){    //获取文件数据bf::path path(req.path);std::stringstream name;name << SHARED_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;//bytes=start-end;//bool ret=RangeParse(range_val,start,rlen);if(ret==false){rsp.status=400;return;}std::cerr<<"range:"<<range_val<<"\n";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;}std::cerr<<"range:"<<range_val<<"\n";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);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<<"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";rsp.status=400;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(SHARED_PATH)){bf::create_directory(SHARED_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);   //搭建服务器   }                                                                                                                              };
#endif

关于客户端的代码实现:
Client.hpp

//实现客户端的功能:                                                                                                            
//1.获取局域网中所有主机的IP地址;
//2.获取在线主机列表(逐个向主机发送配对请求,判断响应状态;
//3.打印在线主机列表,并且向用户选择想要查看的主机共享文件列表;
//4.向选择的主机发送文件列表请求,获取到文件列表
//5.打印文件列表,并且用户选择想要下载的文件;
//6.下载文件(向指定的文件发送指定的文件下载请求)
#ifndef __M_CLI_H__
#define __M_CLI_H__
#include <iostream>
#include <thread>
#include <string>
#include <stdio.h>
#include <fstream>
#include <vector>
#include <fcntl.h>
#include <unistd.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <boost/thread.hpp>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include "httplib.h" #define RANGE_SIZE (1024*1024*100)using namespace httplib;
namespace bf=boost::filesystem;class P2PClient{
private:uint16_t _srv_port;int _host_idx;      //用户选中的IP地址;std::vector<std::string> _online_list;  //在线主机列表td::vector<std::string> _file_list;   //文件列表private:   //私有接口;bool GetAllHost(std::vector<std::string> &list){   //获取局域网中所有的主机列表;struct ifaddrs *addrs=NULL;struct sockaddr_in *ip=NULL;struct sockaddr_in *mask=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=128;i<host;++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 rsp=client.Get("/hostpair");if(rsp && rsp->status==200){std::cerr<<"host"<<i<<"pair success\n";_online_list.push_back(i);}fprintf(stderr,"%s\n",i.c_str());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,&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()){_host_idx=-1;std::cerr<<"choose error\n";return false;}return true;}bool GetFileList(){      //请求文件列表的获取Client client(_online_list[_host_idx].c_str(),_srv_port);auto rsp=client.Get("/list");                                                                                               if(rsp && rsp->status==200){boost::split(_file_list,rsp->body,boost::is_any_of("\n"));}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()){_host_idx=-1;std::cerr<<"choose error\n";return false;}return true;}bool GetFileList(){      //请求文件列表的获取Client client(_online_list[_host_idx].c_str(),_srv_port);auto rsp=client.Get("/list");                                                                                               if(rsp && rsp->status==200){boost::split(_file_list,rsp->body,boost::is_any_of("\n"));}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 rsp=client.Get(uri.c_str(),header);if(rsp && rsp->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,&rsp->body[0],rsp->body.size());if(ret<0){std::cerr<<"file"<<realpath<<"write error\n";close(fd);return;}close(fd);*res=1;std::cerr << 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 rsp=client.Head(path.c_str());if(rsp && rsp->status==200){if(!rsp->has_header("Content-Length")){return -1;}std::string len=rsp->get_header_value("Content-Length");std::stringstream tmp;tmp<<len;tmp>>fsize;}return fsize;}bool DownloadFile(std::string &name){     //下载文件//GET /list/filename Http/1.1//Http/1.1 200 OK                                                                                                           //Content-Length:fsize////FILE//1.获取文件的总长度//2.根据文件总长度和分块大小进行分割线程的下载区域//3.创建线程下载指定文件的指定分块数据//4.同步等待所有线程结束,获取下载结果;std::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<<"file size:"<<fsize<<"\n";     //打印一下文件的大小;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,rlen;start=i * ((int64_t)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";rlen=end-start+1;          //Range:bytes=start-end;int *res=&res_list[i];boost::thread thr(&P2PClient::RangeDownload,this,host,name,start,res);thr_list[i]=std::move(thr);}int ret=true;for(int i=0;i<=count;i++){if(fsize % RANGE_SIZE==0 && i==count){break;}thr_list[i].join();if(res_list[i]==0){std::cerr<<" range "<< i << "download failed\n";    //检查哪一块出错了ret=false;}}if(ret==true){std::cerr<<"download file"<<name<<"success\n";return true;}else{std::cerr<<"dowmload 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;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::vector<std::string> list;switch(choose){case 0:exit(0);default:break;	case 1:GetAllHost(list);GetOnlineHost(list);break;case 2:if(!ShowOnlineHost()){break;}GetFileList();break;case 3:std::string filename;if(ShowFileList(filename)==false){break;                                                                                                              }DownloadFile(filename);break;}}} 
}; 
#endif                                                                                                                         

将代码进行封装:main.cpp


#include "Client.hpp "                                                                                                          
#include "Server.hpp "
void srv_start(){P2PServer server;server.Start(9000);
}int main(){std::thread thr(srv_start);thr.detach();P2PClient client(9000);client.Start;return 0;
}

http://www.ppmy.cn/news/189265.html

相关文章

第五章 工具共享(二)

5.4 使用标准文件夹结构分享工具 建议使用标准的文件夹结构&#xff0c;便于进行共享自定义工具。没有固定的标准文件夹结构&#xff0c;但是可以使用原著给的参考&#xff0c;这个参考只是一个参考&#xff0c;没有展示所有的文件。 根目录Tools下面包含了有一个或者多个自定…

好用的局域网文件共享工具

在公司或者学校实验室&#xff0c;经常会遇到要互相传文件的情况&#xff0c;或者往服务器上发文件的情况&#xff0c;下面就这种应用场景&#xff0c;推荐一下好用的工具 情景一&#xff1a; windows和windows互传 直接使用飞秋[1]&#xff0c;这种情况最普遍。解决方案也很…

SAMBA共享工具安装

1&#xff0c;环境win7 b4位&#xff0c;ubuntu16.04&#xff0c;确定ubuntu已连接到互联网&#xff0c; 执行如下命令下载 Samba 工具&#xff1a;sudo apt-get install samba samba-common 输入Y&#xff0c;按回车继续安装 2&#xff0c;安装完成后&#xff1a;sudo apt-ge…

Chfs 文件共享工具

Chfs 文件共享工具 简介 CuteHttpFileServer/chfs 是一个免费的、HTTP协议的文件共享服务器&#xff0c;使用浏览器可以快速访问。它具有以下特点&#xff1a; 单个文件&#xff0c;核心功能无需其他文件跨平台运行&#xff0c;支持主流平台&#xff1a;Windows&#xff0c;Li…

4种大文件传输工具和软件,用于共享大文件

无论是个人还是与团队一起工作&#xff0c;大文件传输软件和网站都能协助提高工作效率、有效地管理工作内容。疫情原因有时我们不得不居家办公&#xff0c;在这种情况下可以分享文件的工具就显得尤为重要。 每个公司都需要一个文件传输软件&#xff0c;让员工可以上传和分享他…

好用的局域网共享工具有哪些?win10系统如何设置?

简单文件共享是我们日常工作中经常要用到的功能&#xff0c;使用这个功能我们可以很轻松的访问到对面电脑共享出来的文件和打印机。 但是由于这个功能只能在局域网中使用&#xff0c;所以应用场景大大受限。下面给大家推荐一个局域网共享工具外网使用的方法。 由于目前新电脑…

桌面共享工具(可以实现RTMP直播、K歌、投屏等功能)

桌面共享工具&#xff08;可以实现RTMP直播、K歌、投屏等功能&#xff09;是基于ffmpegopencv开发的C&#xff08;vs2013 mfc&#xff09;程序&#xff0c;目前共两个版本&#xff1a;普通版及硬编版&#xff0c;目前主要以普通版开发维护为主&#xff0c;因为普通版是基础&…

局域网文件共享软件 开源_4个用于共享文件的开源工具

局域网文件共享软件 开源 在您的生活中,有时您必须与某人共享一个或多个文件,无论该人是朋友,家庭成员,同事或合作伙伴还是客户。 许多人通过使用诸如ownCloud , Nextcloud或SparkleShare之类的应用程序来完成自己对开源的信念。 这三款游戏既坚固又灵活,但它们并不是镇…