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

前段时间和朋友一起做了一个类似于电驴、迅雷 + 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

 

 

 

未完待续。。。。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值