生活随笔
收集整理的這篇文章主要介紹了
项目[P2P文件下载器]
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
項(xiàng)目介紹:
該項(xiàng)目完一個(gè)在局域網(wǎng)中進(jìn)行附近文件共享下載功能的工具。
能夠進(jìn)行搜索匹配局域網(wǎng)中運(yùn)行工具的主機(jī),獲取到局域網(wǎng)在線的主機(jī)列表 能夠獲取在線主機(jī)所共享的文件信息列表 能夠?qū)χ付ㄖ鳈C(jī)上的文件進(jìn)行多進(jìn)程分塊下載來(lái)提高傳輸效率
?
P2P下載器功能流程:
局域網(wǎng)中的主機(jī)發(fā)現(xiàn) 找到局域網(wǎng)中有哪兒些主機(jī)在使用P2P下載器 看一下附近的主機(jī),有哪兒些文件時(shí)共享的 將這個(gè)主機(jī)上的共享文件下載下來(lái)
客戶端與服務(wù)端進(jìn)行數(shù)據(jù)通信:
1.通信協(xié)議的選擇:HTTP超文本傳輸協(xié)議
HTTP協(xié)議格式
? ? ? ? ? ?首行:
? ? ? ? ? ? ? ? ? ? ?請(qǐng)求首行:請(qǐng)求方法 GET? url 協(xié)議版本 1.1 \r\n
? ? ? ? ? ? ? ? ? ? ? 響應(yīng)首行:協(xié)議版本 響應(yīng)狀態(tài)碼 狀態(tài)碼描述信息\r\n
? ? ? ? ? ? ?頭部:以 key-value 的形式組成一個(gè)鍵值對(duì),并且鍵值對(duì)之間以\r\n進(jìn)行間隔
? ? ? ? ? ? ? 空行:
? ? ? ? ? ? ? 正文:
?
處理細(xì)節(jié):
1.一個(gè)主機(jī)如何發(fā)現(xiàn)附近的主機(jī)--下載器之間的通信
一個(gè)主機(jī)將一個(gè)主機(jī)的配對(duì)需求,發(fā)送到局域網(wǎng)中的所有主機(jī)上,這時(shí)候如果有主機(jī)運(yùn)行了P2P下載器程序,則對(duì)這個(gè)請(qǐng)求,進(jìn)行一個(gè)配對(duì)回應(yīng)。
2.查看附近主機(jī)的共享文件
向指定的主機(jī)發(fā)送一個(gè)獲取文件列表的請(qǐng)求
附近主機(jī)收到請(qǐng)求后,則將共享的目錄下的所有文件名相應(yīng)出去
3.下載指定文件
向指定的主機(jī)發(fā)送獲取文件的請(qǐng)求
指定主機(jī)收到請(qǐng)求后,則打開指定文件
?
?
?服務(wù)器端設(shè)計(jì):
設(shè)計(jì)實(shí)現(xiàn)HTTP服務(wù)端程序,能夠提供瀏覽器客戶端進(jìn)行文件的下載,獲取文件列表功能
服務(wù)端流程:
1.搭建HTTP服務(wù)器
? ? ? ?1.主機(jī)配對(duì)請(qǐng)求處理功能
? ? ? ?2.主機(jī)文件列表獲取處理功能
? ? ? ?3.主機(jī)獲取數(shù)據(jù)獲取功能
2.能夠提供附近主機(jī)配對(duì)功能
3.能夠像附近主機(jī)提供文件列表
4.能夠向附近主機(jī)提供文件下載功能
?
客戶端設(shè)計(jì)
實(shí)現(xiàn)基于服務(wù)器HTTP的分塊傳輸功能實(shí)現(xiàn)多進(jìn)程文件分塊下載功能的下載器,通過(guò)分塊傳輸提高傳輸效率
客戶端流程:
1.獲取局域網(wǎng)中所有的IP地址信息
2.向獲取到的IP主機(jī)地址發(fā)送主機(jī)配對(duì)請(qǐng)求--獲取到配對(duì)成功的主機(jī)IP地址列表
3.打印配對(duì)成功的主機(jī)列表
4.用戶選擇想要獲取哪兒個(gè)主機(jī)的共享文件
5.向指定的這個(gè)主機(jī)發(fā)送文件列表獲取請(qǐng)求 -- 獲取到主機(jī)上的共享文件列表
6.打印所有的文件列表,用戶選擇想要下載哪兒個(gè)共享文件
7.向指定的主機(jī)發(fā)送文件數(shù)據(jù)獲取請(qǐng)求
?
實(shí)現(xiàn)流程:
發(fā)現(xiàn)局域網(wǎng)附近的共享用戶 23 //1. 獲取局域網(wǎng)IP地址列表24 bool GetHostList(std::vector<std::string> &list) {25 struct ifaddrs *addrs;26 getifaddrs(&addrs);27 while (addrs) {28 if (strcmp(addrs->ifa_name, "lo") == 0) {29 addrs = addrs->ifa_next;30 continue;31 }32 sockaddr_in *addr=(sockaddr_in*)addrs->ifa_addr;33 sockaddr_in *mask=(sockaddr_in*)addrs->ifa_netmask;34 if (addr->sin_family != AF_INET) {35 addrs = addrs->ifa_next;36 continue;37 }38 uint32_t net = ntohl((addr->sin_addr.s_addr & mask->sin_addr.s_addr)) ;39 int host = ntohl(~mask->sin_addr.s_addr);40 41 for (int i = 1; i < host; i++) {42 struct in_addr ip;43 ip.s_addr = htonl(net + i);44 list.push_back(inet_ntoa(ip));45 }46 addrs = addrs->ifa_next;47 } 48 return true;49 } ?
列出附近用戶列表,并選擇想要查看的用戶主機(jī)
//打印配對(duì)成功的主機(jī)列表67 void PrintHost() {68 for (int i = 0; i < _host_list.size(); i++) {69 std::cout <<i<<". [" << _host_list[i] << "]\n";70 }71 SelectHost();72 }73 //用戶選擇要獲取哪個(gè)主機(jī)的文件列表74 void SelectHost() {75 std::cout <<"選擇想要查看的主機(jī):";76 fflush(stdout);77 std::cin >> _host_idx;78 GetFileList(_host_list[_host_idx]);79 }
?
獲取指定用戶的文件列表,并選擇想要下載的文件 80 //3.獲取指定主機(jī)的文件列表81 bool GetFileList(std::string &host_addr) {82 httplib::Client client(host_addr.c_str(), 9000);83 auto rsp = client.Get("/list");84 if (rsp && rsp->status == 200) {85 //filename1\nfilename2...86 boost::split(_file_list, rsp->body, boost::is_any_of("\n"));87 }else {88 std::cerr<<"host:["<<host_addr<<"] get file list failed\n";89 }90 return true;91 }92 //4.打印文件列表93 void PrintFile() {94 for (int i = 0; i < _file_list.size(); i++) {95 std::cout << i << ". ["<<_file_list[i]<<"]\n";96 }97 SelectFile();98 }
?
獲取文件的頭信息(主要是獲取文件的長(zhǎng)度信息) 84 void GetFileData(const httplib::Request &req, httplib::Response &rsp){85 // /list/abc.txt -> root/list/abc.txt86 87 std::cerr << "download file:["<<req.path<<"]\n";88 std::string realpath = ROOT_PATH + req.path;89 if (!bf::exists(realpath)) {90 std::cerr << "file:["<<realpath<<"] is not exists\n";91 rsp.status = 404;92 return;93 }94 //bf::file_size() 獲取文件大小95 int64_t fsize = bf::file_size(realpath);96 97 std::ifstream file(realpath, std::ios::binary);98 if (!file.is_open()) {99 rsp.status = 500;100 return ;101 }102 rsp.body.resize(fsize);103 file.read(&rsp.body[0], fsize);104 if (!file.good()) { 105 rsp.status = 500;106 return;107 }108 file.close();109 110 rsp.set_header("Content-Type", "application/octet-stream");111 rsp.status = 200;112 return ;113 }
?
對(duì)獲取到的文件長(zhǎng)度進(jìn)行分區(qū)域劃分下載 99 //選擇文件進(jìn)行下載100 bool SelectFile() {101 std::cout<<"選擇想要下載文件id:";102 fflush(stdout); 103 std::cin >> _file_idx;104 DownLoadFile(_file_list[_file_idx]);105 return true;106 }107 bool DownLoadFile(std::string &filename) {108 std::string host_addr = _host_list[_host_idx];109 httplib::Client client(host_addr.c_str(), 9000);110 auto rsp = client.Get(filename.c_str());111 if (rsp && rsp->status == 200) {112 // /list/filename -> filename113 // ./download/ + filename -> ./download/filename114 boost::filesystem::path path(filename);115 std::string file = path.filename().string();116 std::string realpath = _download_path + file;117 std::ofstream fs(realpath, std::ios::binary);118 if (!fs.is_open()) {119 std::cerr << "open file:["<<realpath<<"] failed\n";120 return false;121 }122 fs.write(&rsp->body[0], rsp->body.size());123 if (!fs.good()) {124 std::cerr << "write file:["<<realpath<<"] failed\n";125 return false;126 }127 fs.close();128 std::cerr << "download file success\n";129 }else {130 std::cerr << "download file failed!\n";131 return false;132 }133 return true;134 } ?
創(chuàng)建多進(jìn)程進(jìn)行分塊文件下載
?
主要功能的接口設(shè)計(jì)
服務(wù)器功能接口:
提供客戶端的主機(jī)配對(duì)功能 void GetHostPair(const httplib::Request &req, httplib::Response &rsp) ?
提供客戶端的文件列表獲取功能
void GetFileList(const httplib::Request &req, httplib::Response &rsp) ?
提供客戶端的文件下載功能 void GetFileData(const httplib::Request &req, httplib::Response &rsp) ?
客戶端功能接口:
提供能夠發(fā)現(xiàn)匹配局域網(wǎng)附近主機(jī)的功能 bool GetHostList(std::vector<std::string> &list) ?
提供能夠獲取指定主機(jī)共享文件列表的功能 bool GetFileList(std::string &host_addr) ?
提供能夠下載指定主機(jī)下指定共享文件的功能 bool DownLoadFile(std::string &filename)
其它接口包括httplib.h的基本使用?
及ifaddr.c:
struct ifaddrs *addrs = NULL;
int getifaddrs(struct ifaddrs **ifap); /*獲取本機(jī)網(wǎng)卡信息*/返回值:0-成功 -1-失敗
void freeifaddrs(struct ifaddrs *ifa); /*釋放網(wǎng)卡信息存儲(chǔ)資源*/
struct ifaddrs
{struct ifaddrs *ifa_next; /* 鏈表指針,指向下一個(gè)網(wǎng)卡信息 */char *ifa_name; ? ? ? /* 網(wǎng)卡名稱*/unsigned int ifa_flags; ? /* Flags as from SIOCGIFFLAGS ioctl. */struct sockaddr *ifa_addr; ? /* 地址結(jié)構(gòu)*/struct sockaddr *ifa_netmask; /* 子網(wǎng)掩碼*/union{/* At most one of the following two is valid. If the IFF_BROADCASTbit is set in `ifa_flags', then `ifa_broadaddr' is valid. If theIFF_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# endifvoid *ifa_data; ? ? ? /* Address-specific data (may be unused). */
};
但要注意的是如果是在LINUX系統(tǒng)下進(jìn)行的操作,那么就必須要關(guān)閉防火墻
su root
systemctl stop firewalld
?
?
?
?
?
?
?
?
?
?
?
總結(jié)
以上是生活随笔 為你收集整理的项目[P2P文件下载器] 的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。