eMule分析之CEd2KLink类及其派生类分析
邵盛松2008年10月6日
CEd2KLink类主要功能是从ED2K链接字符串中找到需要连接主机.
CEd2KLink类派生出三个类分别是CED2KFileLink ,CED2KServerLink,CED2KServerListLink
CED2KFileLink类的主要作用的从包含关键字file的字符串中的找到需要连接主机
CED2KServerLink类的主要作用的从包含关键字server的字符串中的找到需要连接主机
,CED2KServerListLink 类的主要作用的从包含关键字serverlist的字符串中的找到需要连接主机
类定义如下
class CED2KLink
{
public:
static CED2KLink* CreateLinkFromUrl(const TCHAR* url);
virtual ~CED2KLink();
typedef enum { kServerList, kServer , kFile , kInvalid } LinkType;
virtual LinkType GetKind() const = 0;
virtual void GetLink(CString& lnk) const = 0;
virtual class CED2KServerListLink* GetServerListLink() = 0;//下面是三个纯虚类
virtual class CED2KServerLink* GetServerLink() = 0;
virtual class CED2KFileLink* GetFileLink() = 0;
};
GetNextString函数用于截取字符串,
该函数具有多态性.都表示同一个功能这个给一个函数示例添加注释,
功能:截取字符串
参数说明:
rstr表示要操作的字符串
pszTokens表示需要查找的字符
riStart表示开始查找的位置
返回值
类型:CString
截取从riStart开始到所要查找的字符的位置之间的字符串(不包括所要查找的字符串)
CString GetNextString(const CString& rstr, LPCTSTR pszTokens, int& riStart)
{
CString strResult;
if (pszTokens != NULL && riStart != -1)//如果字符串不为空并且,开始查找数据的位置不是-1
{
int iToken = rstr.Find(pszTokens, riStart);
if (iToken != -1)//返回值为-1,表示没有查找到,iToken是所要查找数据的下标(从开始计算)
{
int iLen = iToken - riStart;
if (iLen >= 0)
{
strResult = rstr.Mid(riStart, iLen);//截取字符串从riStart开始,截取长度是iLen个
riStart += iLen + 1;
}
}
else
{
strResult = rstr.Mid(riStart);
riStart = -1;
}
}
return strResult;
}
:CreateLinkFromUrl函数注释
CED2KLink* CED2KLink::CreateLinkFromUrl(const TCHAR* uri)
{
/* 基本ed2k链接: ed2k://|file|<文件名称>|<文件大小>|<文件哈希值>|/
eD2k片段哈希值链接 ed2k://|file|<文件名称>|<文件大小>|<文件哈希值>|p=<片段哈希值>|/
eD2k来源链接 ed2k://|file|<文件名称>|<文件大小>|<文件哈希值>|/|sources,<IP:端口>|/
eD2k主机链接 ed2k://|file|<文件名称>|<文件大小>|<文件哈希值>|/|sources,<主机名称:端口>|/
eD2kHTTP 来源链接 ed2k://|file|<文件名称>|<文件大小>|<文件哈希值>|s=http://any.com/文件名称|/
eD2k根哈希值链接 ed2k://|file|<文件名称>|<文件大小>|<文件哈希值>|h=<根哈希值>|/
直接服务器链接 ed2k://|server|1.1.1.1|1986|/
*/
CString strURI(uri);
int iPos = 0;
CString strTok = GetNextString(strURI, _T("|"), iPos);//截取字符串,第一次截取到"|"为止
if (strTok == _T("ed2k://"))//判断strURL的开头是否是ed2k://
{
strTok = GetNextString(strURI, _T("|"), iPos);//此时iPos的值就是第一次次查找"|"的索引+1
if (strTok == _T("file"))//判断第二段字符串是否是file
{
CString strName = GetNextString(strURI, _T("|"), iPos);//此时iPos的值就是第二次查找"|"的索引+1
if (!strName.IsEmpty())//判断表示文件名称的字符串是否为空
{
CString strSize = GetNextString(strURI, _T("|"), iPos);
if (!strSize.IsEmpty())//判断表示文件大小的字符串是否为空
{
CString strHash = GetNextString(strURI, _T("|"), iPos);
if (!strHash.IsEmpty())//判断表示文件哈希值的字符串是否为空
{
//文件哈希值后面的字符串表示各种链接
CStringArray astrEd2kParams;
//声明一个CString类型的数组,CStringArray类用于表示CString的数组
bool bEmuleExt = false;
CString strEmuleExt;
CString strLastTok;
strTok = GetNextString(strURI, _T("|"), iPos);
//从文件哈希值后面的"|",开始截取字符串
while (!strTok.IsEmpty())
{
strLastTok = strTok;
if (strTok == _T("/"))
{
if (bEmuleExt)
break;
bEmuleExt = true;
}
else
{
if (bEmuleExt)
{
if (!strEmuleExt.IsEmpty())
strEmuleExt += _T('|');
strEmuleExt += strTok;
}
else
astrEd2kParams.Add(strTok);
}
strTok = GetNextString(strURI, _T("|"), iPos);
}
if (strLastTok == _T("/"))
return new CED2KFileLink(strName, strSize, strHash, astrEd2kParams, strEmuleExt.IsEmpty() ? (LPCTSTR)NULL : (LPCTSTR)strEmuleExt);
//返回ed2k链接
}
}
}
}
else if (strTok == _T("serverlist"))//判断第二段字符串是否是serverlist
{
CString strURL = GetNextString(strURI, _T("|"), iPos);
if (!strURL.IsEmpty() && GetNextString(strURI, _T("|"), iPos) == _T("/"))
return new CED2KServerListLink(strURL);
}
else if (strTok == _T("server"))//判断第二段字符串是否是server
{
CString strServer = GetNextString(strURI, _T("|"), iPos);
if (!strServer.IsEmpty())
{
CString strPort = GetNextString(strURI, _T("|"), iPos);
if (!strPort.IsEmpty() && GetNextString(strURI, _T("|"), iPos) == _T("/"))
return new CED2KServerLink(strServer, strPort);//产生CED2KServerLink类对象
}
}
}
throw GetResString(IDS_ERR_NOSLLINK);
}
下面对对eMule中的CED2KLink类及其派生类进行简单模拟
#include "iostream"
using namespace std;
class Base
{
public:
static Base* function();
virtual class Derived1* print1()=0;
};
class Derived1:public Base
{
public:
Derived1(){cout<<"构造Derived1"<<endl;}
virtual Derived1* print1();
};
Derived1* Derived1::print1()
{
cout<<"print1"<<endl;
return 0;
}
Base* Base::function()
{
cout<<"function"<<endl;
Base* p=new Derived1();
p->print1();
return 0;
}
int main()
{
Base::function();
return 0;
}
代码已在VC++2005下调试通过
语法说明:在基类的静态函数中产生派生类对象
也就在CED2KLink类的CreateLinkFromUrl函数中可以产生它的三个派生类的对象
参考
eMule 0.47 源码
http://www.emule-project.net
Emule Document