SOcketベースのリソース共有プラットフォームの実現(一)


この間、友達と一緒にロバ、迅雷+MSNツールのようなブランクモデルを作りました.基本的にすべての機能はsocket通信レベルから実現されています.
全体アーキテクチャはC/Sアーキテクチャであり、MFCを用いて実現される.技術的には古いもので、この文章は主にロバのようなソフトウェアの設計構想と一部のコードフレームワークを紹介します.
我々が実現したコードはあまり最適化されておらず,設計構想の証拠にすぎない.
 
私が最初にこの小さなソフトウェアを作ったのは、小さなネットワークの中でみんなの資源の共有と交流を便利にすることです.
誰もが自分のファイルの一部を共有することができ、もちろんこれはWINDOWSの共有フォルダやLINUXのSAMBAで実現できますが、私が共有ソースを知らない場合、リソースを得るのは難しいです.ある人は、WINDOWSのネット上の隣人の中で直接ローカルエリアネットワークの上でみんなが共有する資源を見ることができて、しかし私は各種のネットの設置の関係のためかもしれないことを発見して、ネット上の隣人の中で私はいつも他の人が共有する資源を見ることができません.
 
そこで当时私はWINDOWSのいくつかのAPIを使って、(具体的に何なのか忘れて、他人の共有ディレクトリを探知して遍歴することができます)、书く効果もとてもよくなくて、第1はとても遅くて、第2はやはり不完全で、第3はコントロールできなくて、そのパッケージ度は高すぎて、N多技术の细部を隠します.
 
それから私は、やはりsocketに基づいて、底から始めたいと思っていました.
ソースを知らない場合,各ソースの共有リソースをどのように探知し,収集するか.--答えはすぐに浮かび上がって、1台のサーバーを作って、みんなはすべてサーバーに接続して、それに自分のここの資源の情況を教えて、それからみんなは統一してサーバーからネット上の共有資源を照会して、それからクライアントのポイント対ポイント接続の伝送ファイルを創立します.
 
 
 
プログラムの全体的なアーキテクチャは簡単で、以下の本文の主旨は一歩一歩このソフトウェアの実現におけるいくつかの要点を皆さんに教えることです.
 
1.内部契約
 
私たちのクライアントはサーバー側と「交流」する必要があります.システム内部で互いに識別できる言語が必要です.このようなプロトコルは完全に自分で設計することができます.
私が実装で採用したUDP通信は、各UDPパケットの最初の1バイトが命令バイトであり、その後、各命令のフォーマットに従ってパラメータを接続します.たとえば、社内プロトコルの一部のコード:
 
/*********************************************/
// 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サーバ(クライアント自動アップグレードパッケージを公開する)として機能することができる.
 
では、私たちは核心思想を総括して、クライアントに関わらずサーバーの端に関わらず、すべて1つのtcp listenerがあるべきで、絶えずネット上で到来するTCPの要求を傍受して、1つの要求が来るたびに、それと接続を創立して、しかも単独で1つのスレッドを増やしてその通信とファイルの伝送を行います--私はこのメカニズムをTCPファイルの伝送グループの管理と言います.
 
トランスポート・クラスタ管理には、次の点が含まれます.
1.要求をリスニングし、接続を確立する.
2.接続にスレッドを追加する.
3.制御伝送サービス;
4.転送を終了し、スレッドを閉じます.
 
次に、トランスポート・グループ管理のコア・セクション・コードを示します.
 
大まかに説明すると、TCPServerManagerは伝送群管理であり、TCP伝送のコンテナクラスとしてTCPTaskManagerを接続するたびに1つずつ起動し、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

 
 
 
未完待续...