一个基于socket的资源共享平台的实现(一)

介绍了自制的一款类似电驴的P2P文件共享软件的设计思路与部分代码框架,包括内部协议设计、UDP通信、TCP文件传输管理等核心技术点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前段时间和朋友一起做了一个类似于电驴、迅雷 + MSN工具的毛坯模型,基本上所有功能都是从socket通信级别向上实现。

整体架构为C/S架构,使用MFC实现。技术上都是很老的东西,此文主要介绍类似于 电驴 的这样一个软件的设计思路和部分代码框架。

我们实现的代码不是很优化,仅为设计思路的佐证。

我最初做这个小软件的想法是,方便一个小型网络中大家的资源共享和交流。

每个人都能共享出自己的一部分文件,当然这个可以通过WINDOWS的共享文件夹或者LINUX的SAMBA实现,不过假如在我并不知道共享源的情况下,就很难获得资源了。有人说,直接在WINDOWS的网上邻居里可以看到局域网上大家共享的资源,但是我发现可能由于各种网络设置的关系,在网上邻居里我经常看不到其他人共享的资源。

于是当时我用WINDOWS的几个API,(忘了具体是什么了,可以探测和遍历他人共享目录),写出来效果也很不好,第一很慢,第二还是收不全,第三不可控,其封装度太高,隐藏N多技术细节。

于是后来我想,还是基于socket,从底层做起。

在不知道源的情况下,我们如何探测、收集到各个源的共享资源呢?—— 答案很快浮出水面,弄一台服务器,大家都连接服务器,告诉它自己这儿的资源情况,然后大家统一从服务器查询网络上的共享资源,然后建立客户端的点对点连接传输文件。

程序的整体架构很简单,下面本文的主旨在于一步步的告诉大家在此软件实现中的一些要点。

1. 内部协议

我们的客户端需要与服务器端“交流”,就得有一套系统内部能被互相识别的语言,这样一套协议完全可以咱们自己设计。

我在实现中采用的UDP通信,每个UDP包 头一个字节为 指令字节,其后按照每个指令的格式跟接参数。例如我的“内部协议”部分代码:

/*********************************************/ // c->s 用户心跳 #define NS_UDP_LIVING 0x03 // c->s 用户更新共享信息 #define NS_UDP_UPDATE 0x04 // c->s 用户搜索 #define NS_UDP_SEARCH 0x05 // c->s 获取在线用户列表 #define NS_UDP_GET_ONLINE_USERS 0x06 // c->s 申请广播消息 #define NS_UDP_CLIENT_BORADCAST 0x07 // c->s 申请下载新版本客户端 #define NS_UDP_CLIENT_GETEXE 0x08 /*********************************************/ // s->c 用户登录成功 #define NS_UDP_LOGIN_SUCCESS 0x71 // s->c 传送搜索结果 #define NS_UDP_PUSHINFO 0x72 // s->c 传送在线用户列表 #define NS_UDP_PUSH_ONLINE_USERS 0x73 // s->c 广播消息 #define NS_UDP_BROADCAST_MESSAGE 0x74 // s->c 服务器重启,踢出所有用户 #define NS_UDP_SERVER_RESTART 0x75 // s->c 重新收集共享资料 #define NS_UDP_RECOLLECT_SHAREFILES 0x76 // s->c 踢出用户 #define NS_UDP_KICK 0x77 // s->c 客户端更新包 #define NS_UDP_CLIENT_UPDATE 0x78 /*********************************************/ // c->c 文件获取 #define NS_UDP_GETFILE 0x80 // c->c 文件获取许可 #define NS_UDP_ALLOW_GETFILE 0x81 // c->c 聊天消息 #define NS_UDP_MESSAGE 0x82

如果直接在网络上发送明文,则很容易被别人使用抓包工具抓取,稍加分析则可理解其中的内容,然后别人可以模拟写客户端或者程序来非法访问、攻击你的服务器端和别的客户端。所以这里应该要使用加密算法,在网路上传输加密数据。在我的“毛坯”程序中没有实现这一点,不过,这在互联网上发布的任何一款商用通信程序都是必须的。

2. TCP文件传输及传输群管理。

在一方申请下载的时候,另一方应该响应该请求,为它建立TCP连接。前者我们称TCP客户端、后者为TCP服务端。基于我们的“共享”的思想,每个客户端程序都可能作为TCP客户(下载资源)或者TCP服务器(提供资源下载),同时服务器端也可以作为TCP服务器(发布客户端自动升级包)。

那么我们总结核心思想就是,不管客户端还是服务器端,都应该有一个tcp listener,不断的监听网络上到来的TCP请求,每当过来一个请求时,与其建立连接,并且单独增开一个线程与其通信进行文件传输——我把这个机制叫做TCP文件传输群管理。

传输群管理应该包括以下几点

1. 侦听请求,建立连接;

2. 为连接增开线程;

3. 控制传输服务;

4. 结束传输,关闭线程。

下面给出我们传输群管理的核心部分代码:

大致说明一下,TCPServerManager为传输群管理,每次有连接单独启动一个TCPTaskManager作为TCP传输的容器类,负责管理一个TCP传输任务。

#ifndef NETSHARE_TCP_SERVER_MANAGER_H_ #define NETSHARE_TCP_SERVER_MANAGER_H_ #include "TCPServer.h" #include "NetShareUDP.h" #include <cpplib/MutexLock.h> #include <string> #include <vector> #include <algorithm> using namespace std; class TCPTaskManager; class TCPServerManager; //typedef void (TCPServerManager::*CALLBACK_DELETE)(int); //发送文件数据结构 struct SendFileStructType { string filename; string ip; string dir; DWORD offset; TCPTaskManager* p_manager; }; //TCP子任务管理器 class TCPTaskManager { public: TCPTaskManager( SendFileStructType task ) : m_Speed( 0 ) , m_Task( task ) , m_MaxSpeed( 0 ) , m_IsFinish( FALSE ) , m_TaskHandler( 0 ) { //this->Run(); m_pTCPServerInstance = new TCP_Server(); } ~TCPTaskManager(){} ////////////////////////////////////////////////////////////////////////// void Speed( DWORD speed ) { m_Speed = speed; } DWORD Speed(){ return m_Speed; } void SetMaxSpeed( DWORD speed ) { m_MaxSpeed = speed; m_pTCPServerInstance->SetMaxSpeed( speed ); } //发送完成后调用 //调用该方法并没有回收本类对应对象在TCPServerManager的m_pTasks中存在的实例, //需要在TCPServerManager中再判断m_IsFinish的状态位加以移除。 void Finish() { CloseHandle( m_TaskHandler ); m_IsFinish = TRUE; } bool CheckFinish(){ return m_IsFinish; } TCP_Server* GetTCPServerInstancePtr(){ return m_pTCPServerInstance; } ////////////////////////////////////////////////////////////////////////// //TCP传送数据线程 static DWORD WINAPI TCPSendThreadProc(LPVOID lpParameter) { SendFileStructType* ptype = (SendFileStructType*)(lpParameter); string ip = ptype->ip; string filename = ptype->filename; //TCP_Server ServerInstance; TCP_Server* pServerInstance = ptype->p_manager->GetTCPServerInstancePtr(); pServerInstance->SetDir( ptype->dir ); pServerInstance->BindManager( ptype->p_manager ); pServerInstance->SendFile( ip,TCP_TRANCESPORT_PORT, filename, ptype->offset ); ptype->p_manager->Finish(); return 0; } void Run() { m_Task.p_manager = this; m_TaskHandler = CreateThread( NULL, 0, TCPSendThreadProc, (LPVOID)&m_Task, 0, NULL ); } protected: DWORD m_Speed;//当前速度 DWORD m_MaxSpeed; //最大传输速度 SendFileStructType m_Task; HANDLE m_TaskHandler; bool m_IsFinish; TCP_Server* m_pTCPServerInstance; }; namespace { //检测一个任务是否已经完成 bool CompletedTask( TCPTaskManager* task ) { return ( task->CheckFinish() ); } } //TCP文件传送服务器端管理类 class TCPServerManager { public: TCPServerManager(){} ~TCPServerManager(){} //添加文件传送任务 bool AddTask( SendFileStructType task ); //设置整体最大发送速度 void MaxSpeed( DWORD speed ) { m_MaxSpeed = speed; AdjustSpeed(); } //删除编号为id的下载任务 void Delete( size_t id ) { TaskMutex.Lock(); vector<TCPTaskManager*>::iterator iter = m_pTasks.begin(); for( size_t i = 0; i < id; i++ ) ++iter; delete *iter; m_pTasks.erase( iter ); TaskMutex.Unlock(); AdjustSpeed(); } //移除所有已完成的任务 void ClearCompleteTask() { try { TaskMutex.Lock(); vector<TCPTaskManager*>::iterator new_end = remove_if( m_pTasks.begin(), m_pTasks.end(), CompletedTask ); for( vector<TCPTaskManager*>::iterator iter = new_end; iter != m_pTasks.end(); ++iter ) delete *iter; m_pTasks.erase( new_end, m_pTasks.end()); int k = m_pTasks.size(); TaskMutex.Unlock(); } catch (...) { } } protected: //获取当前整体发送速度 DWORD GetCurrTotalSpeed() { TaskMutex.Lock(); DWORD sum = 0; for( vector<TCPTaskManager*>::iterator iter = m_pTasks.begin(); iter != m_pTasks.end(); ++iter ) { sum += (*iter)->Speed(); } TaskMutex.Unlock(); return sum; } //获取当前传送任务数 int GetTaskNum() { ClearCompleteTask(); return m_pTasks.size(); } //调整所有发送任务的发送速度 //暂时为平均分配 void AdjustSpeed() { if( m_MaxSpeed == 0 || GetTaskNum() == 0 ) return; DWORD SingleMaxSpeed = m_MaxSpeed / GetTaskNum(); TaskMutex.Lock(); for( vector<TCPTaskManager*>::iterator iter = m_pTasks.begin(); iter != m_pTasks.end(); ++iter ) { (*iter)->SetMaxSpeed( SingleMaxSpeed ); } TaskMutex.Unlock(); } private: DWORD m_MaxSpeed; //整体最大发送速度 vector<TCPTaskManager*> m_pTasks; cpplib::resource::Mutex TaskMutex;//访问m_Task的互斥锁 }; #endif

未完待续。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值