需要共享资源,则需要探测本地资源分布情况。
此处我们用的算法比较2……不过还是说说吧。
下面使用MFC的CFileFind实现一个本地文件递归收集器,以jason格式存储文件路径和文件大小:
#ifndef COLLECTER_H_ #define COLLECTER_H_ #include<iostream> #include<vector> #include "StdioFileEx/StdioFileEx.h" #define TargetFile "result.txt" #define CfgFileName "path.txt" using namespace std; struct FileStruct { CString path; __int64 size; }; vector<FileStruct> files; void findfile(CString dir) { CFileFind finder; BOOL bWorking = finder.FindFile(dir + _T("\\*.*")); while (bWorking) { bWorking = finder.FindNextFile(); //列举文件 if( finder.IsDots() == false && finder.IsDirectory() == false ) { FileStruct file; CString tmp = dir + _T("\\") + CString( finder.GetFileName() ); //只传送文件名 //CString tmp = CString( finder.GetFileName() ); file.path = tmp; __int64 iFileLenInByte = (__int64)finder.GetLength(); __int64 size = iFileLenInByte; file.size = size; files.push_back( file ); } //递归访问子目录 if( finder.IsDirectory() && finder.IsDots() == false ) findfile( dir + _T("\\") + CString( finder.GetFileName() ) ); } } /* [{"f_name":"文件名","f_hash":"文件哈希,32字符","f_length":null/片长,数字不要加引号,"f_type":null/"文件类型就后缀吧先","f_time":null/"年代字符串 加双引号","f_intro":"简介,类似年代"},{}...{}] */ void WriteResult() { CStdioFileEx fp; fp.Open(_T(TargetFile),CFile::modeWrite|CFile::modeCreate); fp.WriteString( _T("[")); for( vector<FileStruct>::iterator iter = files.begin(); iter != files.end(); ++iter) { if( iter != files.begin() ) fp.WriteString(_T(",")); CString MyFileSize; MyFileSize.Format(_T("%ld"),iter->size); fp.WriteString(_T("{\"fname\":\"")); fp.WriteString( iter->path ); fp.WriteString(_T("\",")); fp.WriteString(_T("\"fsize\":\"")); fp.WriteString( MyFileSize ); fp.WriteString(_T("\"}")); //fp.WriteString( iter->size ); } fp.WriteString( _T("]")); fp.Close(); } void ReadCfg(CString& path) { CStdioFileEx fp; fp.Open(_T(CfgFileName),CFile::modeRead); fp.ReadString( path ); fp.Close(); } void StartCollect() { CString SearchPath; ReadCfg( SearchPath ); cout<<"searching please wait."<<endl;; findfile( SearchPath ); WriteResult(); cout<<"finish"<<endl; system("pause"); } #endif
然后定期收集,对收集结果MD5,若发生变化,则上传服务器。
服务器端使用一个数据结构维护所有资源站资源,对于用户的搜索,我们此处使用最简单的比较方法,看是否包含子串,此处就不详加介绍了。
服务器对所有的客户端进行集中管理,需要维护一张在线用户列表。
关于服务器如何探测资源站是否在线,TCP主动的的连接与断开可以检测到,但是若是被动的断线等,是无法正确响应的。所以此处我们还是使用心跳包模型——客户端每隔一段时间就向服务器发送心跳包,证明自己还“活着”,服务器若长时间没有收到某个客户端的心跳,则认为它“死掉”了,就从在线列表里将其KICK。
服务器端我们是使用的CONSOLE管理,实际就是单开一个control线程,可以由管理员输入命令进行管理。如查询在线列表、查询资源、踢出用户、广播消息等,这里也不加详细介绍了。
服务器需要维护LOG文件,如下所示:
【2010-01-25 9:0:24】开启服务器
【2010-01-25 9:0:31】127.0.0.1登入服务器
【2010-01-25 9:0:31】127.0.0.1申请搜索,关键字 =
【2010-01-25 9:1:32】127.0.0.1长时间未响应,从服务器移除
【2010-01-25 9:3:20】开启服务器
【2010-01-25 9:3:23】0.0.0.0申请搜索,关键字 =
【2010-01-25 9:3:30】开启服务器
【2010-01-25 9:3:34】127.0.0.1登入服务器
【2010-01-25 9:3:34】127.0.0.1申请搜索,关键字 =
【2010-01-25 9:3:37】0.0.0.0申请搜索,关键字 =
【2010-01-25 9:3:42】0.0.0.0申请搜索,关键字 = 1
【2010-01-25 9:4:14】127.0.0.1申请搜索,关键字 =
【2010-01-25 9:5:19】127.0.0.1广播消息:sss
【2010-01-25 9:5:21】127.0.0.1广播消息:ahaha
【2010-01-25 9:5:23】127.0.0.1申请搜索,关键字 =
【2010-01-25 9:6:0】127.0.0.1长时间未响应,从服务器移除
【2010-01-25 9:7:9】127.0.0.1登入服务器
【2010-01-25 9:7:9】127.0.0.1申请搜索,关键字 =
【2010-01-25 9:7:46】127.0.0.1长时间未响应,从服务器移除
【2010-01-25 9:9:25】127.0.0.1登入服务器
【2010-01-25 9:9:26】127.0.0.1申请搜索,关键字 =
【2010-01-25 9:14:39】127.0.0.1登入服务器
【2010-01-25 9:15:15】127.0.0.1长时间未响应,从服务器移除
【2010-01-25 9:17:33】127.0.0.1登入服务器
【2010-01-25 9:17:33】127.0.0.1申请搜索,关键字 =
【2010-01-25 9:17:42】127.0.0.1申请搜索,关键字 =
【2010-01-25 9:18:41】127.0.0.1长时间未响应,从服务器移除
【2010-01-25 9:19:7】127.0.0.1登入服务器
【2010-01-25 9:19:8】127.0.0.1申请搜索,关键字 =
【2010-01-25 9:19:45】127.0.0.1长时间未响应,从服务器移除
【2010-01-25 9:20:6】127.0.0.1登入服务器
【2010-01-25 9:20:7】127.0.0.1申请搜索,关键字 =
【2010-01-25 9:21:56】127.0.0.1长时间未响应,从服务器移除
【2010-03-10 14:24:49】开启服务器
【2010-03-10 14:25:50】59.175.191.118登入服务器
【2010-03-10 14:28:18】127.0.0.1登入服务器
【2010-03-10 14:28:18】127.0.0.1申请搜索,关键字 =
【2010-03-10 14:29:32】系统广播消息:test
【2010-03-10 14:29:32】系统广播消息:test
【2010-03-10 14:30:44】127.0.0.1长时间未响应,从服务器移除
【2010-03-10 14:30:53】123.118.15.209登入服务器
【2010-03-10 14:30:54】123.118.15.209申请搜索,关键字 =
这里是我的服务器日志类。
需要注意的是由于多线程写日志,需要线程互斥访问log文件,注意 is_busy 变量。
#ifndef NETSHARE_LOG_H_ #define NETSHARE_LOG_H_ #include <string> #include <vector> #include <fstream> #include <ctime> using namespace std; //服务器日志管理类 class NS_Log { public: NS_Log( string filename ) : logfile( filename.c_str(), ios::app ) , is_busy( false ) {} ~NS_Log() { logfile.close(); } void Write( string dat ) { while( is_busy ) //互斥 { Sleep( 20 ); } is_busy = true; string now_time = GetNowTime(); logfile<<"【"<<now_time<<"】"<<dat<<endl; is_busy = false; } private: //获取当前时间 string GetNowTime() { char pTime[1000]; int year=0,mon=0,day=0,hour=0,min=0,sec=0; time_t now_time; now_time = time(NULL); struct tm *m_tm; m_tm = gmtime(&(time_t)now_time); year = m_tm->tm_year+1900; mon = m_tm->tm_mon+1; day = m_tm->tm_mday; hour = m_tm->tm_hour; min = m_tm->tm_min; sec = m_tm->tm_sec; sprintf(pTime, "%04d-%02d-%02d %d:%d:%d", year, mon, day, hour, min, sec); return string( pTime ); } fstream logfile; bool is_busy; }; #endif
未完待续……