小李子成熟了

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

前言:

之前在学校时老师经常发一些文件让我们下课学习,我们宿舍经常派一个代表下载了回来共享给其他人,为了方便宿舍间文件的共享,就有了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

 

posted on 2020-07-06 15:41  小李子成熟了  阅读(130)  评论(0编辑  收藏  举报