前言:
之前在学校时老师经常发一些文件让我们下课学习,我们宿舍经常派一个代表下载了回来共享给其他人,为了方便宿舍间文件的共享,就有了Bridge transpor该项目的研究。
项目简介:
该项目是为了实现任意两台主机之间的文件下载,确保从一个指定的主机上下载指定的文件,也可以将自己的文件提供给别人下载。主要分为客户端和服务端两大模块。
客户端:
1、查看网络中的共享主机(向网络中广播配对请求)
2、选择一个主机获取文件列表(向指定主机发送获取列表请求)
3、下载指定文件(向指定主机发送下载指定文件请求)
服务端:对客户端的请求作出正确的响应并提供服即可。
详细设计:
客户端:
1.查看网络中的共享主机;
(1)获取网卡信息(主机ip+mask),进而得到局域网中的所有ip地址列表 ;
(2)对在线主机创建线程进行配对;
(3)等待所有线程主机配对完成,判断配对结果,并将配对成功的主机ip打印出来供用户选择;
协议选择:
udp协议自带局域网广播功能,但有可能丢包,为了加深对tcp协议的学习,同时也为了文件传输的安全问题,采用tcp协议进行通信。
http协议比较常用并有一定的自定制功能,为了加深学习,选择http进行网络通信
2.获取文件列表接口;
(1)向服务端发送一个文件列表获取请求
(2)得到响应之后,解析正文(文件名称)
(3)打印服务端响应的文件名称列表供用户选择
3.下载指定主机上的指定文件供下载
(1)向服务端发送文件下载请求
(2)得到相应结果,响应结果中的body正文就是文件数据
(3)创建文件,将文件数据写入文件中,关闭文件
下载文件过程中如果文件过大则采用分块传输。
服务端:
1.接收到主机配对请求,则作出200响应;
2.接收到文件列表请求
(1)检测获取指定共享目录下的文件信息;
(2)将所有的文件名组织成为http响应正文;
3.接收到指定文件下载请求
(1)通过文件名检测文件是否存在;
(2)检测文件是否是一个普通文件
(3)打开文件读取文件数据作为http响应正文响应给客户端;
代码模块设计:
获取网卡信息模块:
class AdapterUtil { public: static bool GetAllAdapter(std::vector<Adapter>*list)//获取网卡信息,返回信息数组 PIP_ADAPTER_INFO p_adapters = new IP_ADAPTER_INFO(); uint64_t all_adapter_size = sizeof(IP_ADAPTER_INFO); //GetAdaptersInfo()是win下获取网卡信息的接口---网卡信息有可能有多个,因此传入一个指针 //因为空间不足,因此有一个输出型参数,用于向用户返回所有的网卡信息空间大小。 int ret = GetAdaptersInfo(p_adapters, (PULONG)&all_adapter_size); if (ret == ERROR_BUFFER_OVERFLOW)//这个错误表示缓冲区空间不足 { //重新给指针申请空间 delete p_adapters; p_adapters = (PIP_ADAPTER_INFO)new BYTE[all_adapter_size]; GetAdaptersInfo(p_adapters, (PULONG)&all_adapter_size);//重新获取网卡信息 } while (p_adapters) { Adapter adapter; inet_pton(AF_INET, p_adapters->IpAddressList.IpAddress.String,&adapter._ip_addr);//将一个点分十进制的ip地址转换为网络字节序的ip地址 inet_pton(AF_INET,p_adapters->IpAddressList.IpMask.String,&adapter._mask_addr); if (adapter._ip_addr == 0) { p_adapters = p_adapters->Next; continue; } list->push_back(adapter); p_adapters = p_adapters->Next; } delete p_adapters; return true; } };
客户端模块:
class Client { public: bool Start() { //客户端程序需要循环运行,因为下载文件不是只下载一次 //循环运行每次下载一个文件之后都会重新进行主机配对(不合理) while (1) { GetOnlineHost(); } return true; } //主机配对的线程入口函数 void HostPair(Host *host) //获取在线主机 bool GetOnlineHost() //获取文件列表 bool GetShareList(const std::string &host_ip) //下载文件,若文件比较大,一次性下载较危险 bool RangeDownload(const std::string &host_ip, const std::string &filename) private: std::vector<Host> _online_host; };
服务端模块:
class Server { public: bool Start() { //std::cout << "服务端已经接收到配对请求\n"; //添加针对客户端请求的处理方式对应关系 _srv.Get("/hostpair", HostPair); _srv.Get("/list", ShareList); //.表示除\n或\r以外的任意字符 *表示匹配前面字符任意次 _srv.Get("/download/.*", DownLoad);//正则表达式,将特殊字符以指定格式,表示具有关键特征的数据 _srv.listen("0.0.0.0", P2P_PORT); return true; } private: //对客户端进行的配对请求做出200响应; static void HostPair(const httplib::Request &req, httplib::Response &rsp) //对客户端的 文件列表请求做出正确响应 static void ShareList(const httplib::Request &req, httplib::Response &rsp) //对客户端的文件下载做出正确响应 static void DownLoad(const httplib::Request &req, httplib::Response &rsp) private: httplib::Server _srv; };
项目的技术点:
多线程/boost库中的一些目录操作/网络传输/http协议/tcp协议/c++ STL
项目的扩展点:
1.跨网络间的文件传输
2.断点续传
点击查看源码:https://github.com/MissLiDailyStruggle/C_plus_plus/tree/master/Bridge%20transport