`
rcfalcon
  • 浏览: 227979 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

一个基于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

 

 

 

未完待续。。。。

分享到:
评论

相关推荐

    基于socket的文件传输

    总的来说,这个项目提供了一个基础的Socket文件传输模型,通过实践可以加深对Java网络编程的理解,为构建更复杂的应用,如聊天室、文件共享系统等打下坚实基础。对于开发者来说,熟练掌握Socket编程不仅可以增强解决...

    Linux上实现基于Socket_的多进程实时通信

    在Linux系统中,实现基于Socket的多进程实时通信是一项重要的技术,它允许不同的进程间高效地交换数据。本文将详细介绍如何创建一个通信服务器(server)来作为中介,处理多个客户端(client)的连接和通信请求。 ...

    用基于Socket做的类似资源管理器的文件共享

    本项目“用基于Socket做的类似资源管理器的文件共享”旨在创建一个简易的文件共享系统,其设计灵感来源于Windows资源管理器,使用户能够方便地进行文件的上传和下载,同时在操作过程中提供进度显示。 首先,Socket...

    基于Socket的IPC消息平台设计

    基于Socket的IPC消息平台为进程间通信提供了一个灵活、高效且易于集成的解决方案。通过线程池、消息队列和消息传输通道等关键技术的应用,不仅提高了系统的性能和吞吐量,还实现了真正的跨平台和跨语言特性,极大地...

    Linux下基于socket多线程并发通信的实现

    总结来说,Linux下的多线程并发通信基于socket实现,结合TCP/IP协议,能够高效地处理多个客户端的并发请求。开发者需要理解套接字的概念、类型以及编程原理,同时掌握多线程编程技巧,包括线程安全、线程池等,以...

    QT实现的基于TCP Socket的共享白板.7z

    在本项目中,“QT实现的基于TCP Socket的共享白板”是一个利用QT库构建的、通过TCP Socket进行通信的多人协作工具。下面将详细介绍QT库、TCP Socket以及共享白板的相关知识点。 1. QT库: - QT库提供了一整套的C++...

    基于SOCKET和多线程的应用程序间通信技术的研究.pdf

    基于SOCKET和多线程的应用程序间通信技术,不仅可以实现跨平台的数据通信,还能在保证数据准确性和完整性的同时,提高系统的响应速度和处理能力。通过对多线程的合理利用,可以有效地分配系统资源,优化数据处理流程...

    基于Socket的多用户网络游戏

    本项目“基于Socket的多用户网络游戏”是一个典型的利用Socket实现的多人在线交互游戏,以井字游戏(Tic-Tac-Toe)为例,展示了如何通过网络连接让多个玩家在同一平台上进行实时对战。 首先,我们要理解什么是...

    Linux下用Socket和多线程实现简单聊天室

    - **线程概念**:线程是进程中的一个执行流,同一进程内的多个线程可以并发执行,共享进程资源,提高程序并发性能。 - **创建线程**:在Linux中,可以使用`pthread_create()`函数创建新的线程,传入线程函数指针和...

    Java基于Socket文件传输示例

    Java基于Socket文件传输示例是一种常见的网络编程应用场景,主要用于实现两个网络节点间的文件共享和交换。Socket编程是Java网络通信的基础,它提供了低级别的、面向连接的、双向的数据传输通道。在这个示例中,我们...

    SOCKET实现远程算术运算(简洁经典实用)

    综合以上,这个项目通过运用SOCKET实现网络通信,利用多线程提升并发处理能力,结合非阻塞模式确保服务的实时性,以及使用STL优化数据管理和算法执行,构建了一个高效且实用的远程算术运算系统。对于想要学习网络...

    Android 基于Socket 的IPC通信

    以上就是基于Socket的Android IPC通信的基本原理和实现步骤。通过这种方式,不同Android进程可以相互通信,实现复杂的功能,例如文件传输、实时消息推送等。但需要注意的是,Socket通信可能会消耗较多的系统资源,...

    C#多线程与Socket聊天室的实现

    本文将深入探讨如何使用C#语言实现一个基于TCP/IP协议的多线程Socket聊天室。这个聊天室功能允许局域网内的多台计算机进行实时信息交互,虽然没有在广域网环境下测试,但在局域网内能有效工作。 首先,我们要理解...

    基于socket聊天工具

    总结来说,这个基于Socket的聊天工具项目涵盖了网络编程的核心概念,如TCP/IP协议、Socket接口、即时通讯实现、文件传输机制和屏幕截图共享。同时,由于提供了源代码,它对于开发者而言,是一个实践和学习网络编程的...

    应用SOCKET实现网络通信

    SOCKET编程中,创建SOCKET后需要绑定一个IP地址和端口号,端口号可以唯一标识网络中的一个进程,IP地址则用于标识不同计算机之间的通信。在基于Windows平台的SOCKET编程中,通常会使用Winsock(Windows Sockets)API...

    LabVIEW环境下远程资源共享及Dat Socket实现

    随着互联网的普及,虚拟仪器的网络化趋势日益凸显,LabVIEW作为虚拟仪器的重要开发平台,提供了多种网络通信方式以满足远程测试、控制和资源共享的需求。本文主要探讨LabVIEW中的TCP、RDA、浏览器方式和DataSocket...

    Python Tornado实现WEB服务器Socket服务器共存并实现交互的方法

    要实现Web服务器和Socket服务器之间的通信,你可以创建一个共享的数据结构,如全局变量或队列,两者都可以访问。例如,Web服务器接收到一个HTTP请求,处理后将数据放入队列,Socket服务器定期检查队列并发送数据给...

    基于socket并发网络通信

    在IT行业中,网络通信是计算机科学的一个重要领域,特别是在分布式系统和互联网应用中。Socket编程是一种基础且核心的技术,它提供了进程间通信(IPC)的能力,使得运行在不同机器上的程序能够相互通信。本篇将详细...

    基于socket的聊天工具(含源码).rar

    【标题】: "基于socket的聊天工具(含源码)" 是一个网络编程项目,它使用了Socket编程技术来实现客户端和服务器之间的实时通信。Socket是网络编程中的基本接口,允许两个程序通过网络进行数据交换,通常用于构建聊天...

    基于Python 洪泛 技术实现了一个资源共享系统【100010973】

    本项目“基于Python 洪泛 技术实现了一个资源共享系统”旨在利用这种技术构建一个用户友好的文件共享和资源下载平台。在这个系统中,用户可以上传文件并让其他用户下载,实现了资源的广泛传播和利用。 首先,让我们...

Global site tag (gtag.js) - Google Analytics