BitTorrent 协议规范(BT协议集合)二一

本文介绍了一种用于BT客户端的Bencode解码器的实现方法。Bencode是一种简单的数据序列化格式,广泛应用于BitTorrent协议中。文章详细解释了如何解析字符串、整数、列表和字典等不同类型的数据,并提供了完整的VC++源代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 BT客户端开始一个下载首先要处理的就是torrent文件.
而torrent文件使用bencoding编码.
所以实现bencoding编码的解析器,就是第一步工作.

Bencoding is done as follows:
Strings are length-prefixed base ten followed by a colon and the string. For e
xample '4:spam' corresponds to 'spam'.
Integers are represented by an 'i' followed by the number in base 10 followed
by an 'e'. For example 'i3e' corresponds to 3 and 'i-3e' corresponds to -3. In
tegers have no size limitation. 'i-0e' is invalid. All encodings with a leadin
g zero, such as 'i03e', are invalid, other than 'i0e', which of course corresp
onds to 0.
Lists are encoded as an 'l' followed by their elements (also bencoded) followe
d by an 'e'. For example 'l4:spam4:eggse' corresponds to ['spam', 'eggs'].
Dictionaries are encoded as a 'd' followed by a list of alternating keys and t
heir corresponding values followed by an 'e'. For example, 'd3:cow3:moo4:spam4
:eggse' corresponds to {'cow': 'moo', 'spam': 'eggs'} and 'd4:spaml1:a1:bee' c
orresponds to {'spam': ['a', 'b']} . Keys must be strings and appear in sorted
order (sorted as raw strings, not alphanumerics).

下面是实现的bencoding解码器的VC++源代码:

 

// BEncode.h: interface for the CBEncode class. 
// 
/////////////////////////////////////////////////////////////////////

#if !defined(AFX_BENCODE_H__4D0BB462_2AE0_45B3_8BE8_19D51B2DBB2E__INCLUDED_) 
#define AFX_BENCODE_H__4D0BB462_2AE0_45B3_8BE8_19D51B2DBB2E__INCLUDED_ 

#if _MSC_VER > 1000 
#pragma once 
#endif // _MSC_VER > 1000 
#pragma warning( disable : 4786 ) 
#pragma warning( disable : 4355 ) 
#include 
#include 
#include 
#include 
using namespace std; 
enum BEncodeParserErrorCode 

  enm_BEncodeErr_noerr 
= 0,//没有错误    
  enm_BEncodeErr_errString,//错误的字符串 
  enm_BEncodeErr_errInt,//错误的整型数据 
  enm_BEncodeErr_errList,//错误的列表 
  enm_BEncodeErr_errDict,//错误的词典结构 
  enm_BEncodeErr_End,//文本结束 
  enm_BEncodeErr_unknown//未知错误 
}; 
enum BEncodeObjectType 

  enum_BEncodeType_Objectbase 
= 0,    
  enum_BEncodeType_String, 
  enum_BEncodeType_Int, 
  enum_BEncodeType_List, 
  enum_BEncodeType_Dict, 
}; 
class CBEncodeObjectBase 

public
  CBEncodeObjectBase(BEncodeObjectType type 
= enum_BEncodeType_Objectbase){m 
_type 
= type;clear();} 
  
virtual ~CBEncodeObjectBase(){}; 
  
void clear(){szPos = NULL;m_error = enm_BEncodeErr_noerr;} 
public
  BEncodeObjectType m_type;   
//对象类型 
  char * szPos;   //对象在字符串中的位置 
  int ilen;//对象的数据长度 
  BEncodeParserErrorCode m_error;//错误值    
}; 
class CBEncodeInt : public CBEncodeObjectBase 

public
  CBEncodeInt() : CBEncodeObjectBase(enum_BEncodeType_Int) {} 
  
virtual ~CBEncodeInt(){}       
public:    
  
int m_iValue;//整型对象的值 
}; 
class CBEncodeString : public CBEncodeObjectBase 

public
  CBEncodeString() : CBEncodeObjectBase(enum_BEncodeType_String) {m_szData 
= 
NULL;} 
  
virtual ~CBEncodeString(){}       
public:    
  
bool getstring(string & strValue) 
  { 
    
if(m_error == enm_BEncodeErr_noerr && m_szData) 
    { 
        strValue.assign(m_szData,m_ilen); 
        
return true
    } 
    
return false
  } 
  
char * m_szData; 
  
int m_ilen; 
}; 
class CBEncodeList : public CBEncodeObjectBase 

public
  CBEncodeList() : CBEncodeObjectBase(enum_BEncodeType_List) {} 
  
virtual ~CBEncodeList(){clear();} 
  
void clear() 
  {          
    list::iterator it; 
    
for(it = m_listObj.begin();it!=m_listObj.end();++it) 
        delete (
*it); 
    m_listObj.clear(); 
  } 
public:    
  list m_listObj; 
}; 
class CBEncodeDict : public CBEncodeObjectBase 

public
  CBEncodeDict() : CBEncodeObjectBase(enum_BEncodeType_Dict) {} 
  
virtual ~CBEncodeDict(){clear();} 
  CBEncodeObjectBase
* getvalue(const char * szName) 
  { 
    map::iterator it 
= m_mapObj.find(szName); 

    
if(it != m_mapObj.end()) 
        
return it->second; 
    
return NULL; 
  } 
  
void clear() 
  {          
    list::iterator it; 
    
for(it = m_listObj.begin();it!=m_listObj.end();++it) 
        delete (
*it); 
    m_listObj.clear(); 
    m_mapObj.clear(); 
  } 
public:    
  map m_mapObj;
// 
  list m_listObj;//真正的对象保存在list中,list是一个nam 
e对象一个value对象.map只是一个映射表,引用了指针而已 
}; 
class CBEncode 

public
  
bool readint(char *szCurPos,int & iendpos,list & list 
Obj); 
  
bool readstring(char *szCurPos,int & iendpos,list & l 
istObj);    
  
bool readlist(char *szCurPos,int & iendpos,list & lis 
tObj);    
  
bool readdict(char *szCurPos,int & iendpos,list & lis 
tObj);    
  
bool parse(const char * szData); 
  CBEncode(); 
  
virtual ~CBEncode(); 
  
void clear() 
  {    
    list::iterator it; 
    
for(it = m_listObj.begin();it!=m_listObj.end();++it) 
        delete (
*it); 
    m_listObj.clear();    
  } 
public
  list m_listObj; 
  CBEncodeObjectBase
* m_plastObj;//解析出来的最后一个对象 
  char * m_szTxt; 
}; 

#endif // !defined(AFX_BENCODE_H__4D0BB462_2AE0_45B3_8BE8_19D51B2DBB2E__INCLUD 
ED_) 

// BEncode.cpp: implementation of the CBEncode class. 
// 
/////////////////////////////////////////////////////////////////////

#include 
"stdafx.h" 
#include 
"BEncode.h" 

/////////////////////////////////////////////////////////////////////
// Construction/Destruction 
/////////////////////////////////////////////////////////////////////

CBEncode::CBEncode() 

  m_plastObj 
= NULL; 
  m_szTxt 
= NULL; 


CBEncode::
~CBEncode() 

  clear(); 


bool CBEncode::parse(const char *szData) 

  
if(szData == NULL||*szData==NULL) 
    
return false
  clear(); 
  m_szTxt 
= (char*)szData; 
  
char * szCurPos = (char*)szData; 
  
int iendpos; 
  
while(*szCurPos) 
  {    
    
if(*szCurPos== 'i'
    { 
        
if(!readint(szCurPos,iendpos,m_listObj)) 
          
break;//遇到任何错误都终止整个解析 
        szCurPos+=iendpos; 
    } 
    
else if(*szCurPos== 'l'
    { 
        
if(!readlist(szCurPos,iendpos,m_listObj)) 
          
break
        szCurPos
+=iendpos; 
    } 
    
else if(*szCurPos== 'd'
    { 
        
if(!readdict(szCurPos,iendpos,m_listObj)) 
          
break
        szCurPos
+=iendpos; 
    } 
    
else          
    { 
        
if(!readstring(szCurPos,iendpos,m_listObj)) 
          
break
        szCurPos
+=iendpos; 
    } 
  } 
  
if(*szCurPos==0&&m_plastObj->m_error == enm_BEncodeErr_noerr) 
    
return true
  
return false

//从当前位置读取一个字符串 
bool CBEncode::readstring(char *szCurPos,int & iendpos,list*> & listObj) 
{    
  
char * szTmp = szCurPos; 
  CBEncodeString 
* pNewString = new CBEncodeString;    
  pNewString
->szPos = szCurPos; 

  
char szLen[20]; 
  
int i = 0
  
while(*szTmp>='0'&&*szTmp<='9'
    szLen[i
++]=*(szTmp++); 
  szLen
=0
  
if(*szTmp==':'
  { 
    
int ilen = atoi(szLen); 
    
if(ilen>0
    {    
        pNewString
->m_szData = ++szTmp; 
        pNewString
->m_ilen = ilen; 
        szTmp
+=ilen; 
    } 
    
else 
        pNewString
->m_error = enm_BEncodeErr_errString; 
  } 
  
else 
    pNewString
->m_error = enm_BEncodeErr_errString; 
  listObj.push_back(pNewString); 
  iendpos 
= szTmp-szCurPos;          
  m_plastObj 
= pNewString; 
  m_plastObj
->ilen = iendpos; 
  
return pNewString->m_error == enm_BEncodeErr_noerr?true:false

//读取一个整型数据 
bool CBEncode::readint(char *szCurPos,int & iendpos,list 
& listObj) 

  
char * szTmp = szCurPos; 
  CBEncodeInt 
* pNewInt= new CBEncodeInt;    
  pNewInt
->szPos = szCurPos; 

  
if(*szTmp == 'i'
  {    
    szTmp
++
    
char szLen[20]; 
    
int i = 0
    
while(*szTmp>='0'&&*szTmp<='9'
        szLen[i
++]=*(szTmp++); 
    szLen
=0
    
if(*szTmp=='e'
    { 
        pNewInt
->m_iValue = atoi(szLen);          
        
++szTmp; 
    } 
    
else 
        pNewInt
->m_error = enm_BEncodeErr_errInt; 
  } 
  
else 
    pNewInt
->m_error = enm_BEncodeErr_errInt; 
  listObj.push_back(pNewInt); 
  iendpos 
= szTmp-szCurPos;    
  m_plastObj 
= pNewInt; 
  m_plastObj
->ilen = iendpos; 
  
return pNewInt->m_error == enm_BEncodeErr_noerr?true:false
}
//读取一个列表 
bool CBEncode::readlist(char *szCurPos,int & iendpos,list 
& listObj) 

  
char * szTmp = szCurPos; 
  CBEncodeList 
* pNewList= new CBEncodeList; 
  pNewList
->szPos = szCurPos; 
  
if(*szTmp == 'l'
  { 
    szTmp
++
    
int ilistendpos; 
    
while(*szTmp!='e'
    { 
        
if(*szTmp== 'i'
        { 
          
if(!readint(szTmp,ilistendpos,pNewList->m_listObj)) 
            
break;//遇到任何错误都终止整个解析 
          szTmp+=ilistendpos; 
        } 
        
else if(*szTmp== 'l'
        { 
          
if(!readlist(szTmp,ilistendpos,pNewList->m_listObj)) 
            
break
          szTmp
+=ilistendpos; 
        } 
        
else if(*szTmp== 'd'
        { 
          
if(!readdict(szTmp,ilistendpos,pNewList->m_listObj)) 
            
break
          szTmp
+=ilistendpos; 
        } 
        
else          
        { 
          
if(!readstring(szTmp,ilistendpos,pNewList->m_listObj)) 
            
break
          szTmp
+=ilistendpos; 
        } 
    }    
    
if(*szTmp!='e'||m_plastObj->m_error != enm_BEncodeErr_noerr) 
        pNewList
->m_error = enm_BEncodeErr_errList; 
    
else 
        szTmp
++
  } 
  
else 
    pNewList
->m_error = enm_BEncodeErr_errList; 
  listObj.push_back(pNewList); 
  iendpos 
= szTmp-szCurPos; 
  m_plastObj 
= pNewList; 
  m_plastObj
->ilen = iendpos; 
  
return pNewList->m_error == enm_BEncodeErr_noerr?true:false

//读取一个字典 
bool CBEncode::readdict(char *szCurPos,int & iendpos,list 
& listObj) 

  
char * szTmp = szCurPos; 
  CBEncodeDict 
* pNewDict= new CBEncodeDict; 
  pNewDict
->szPos = szCurPos;    
  
if(*szTmp == 'd'
  {       
    szTmp
++
    
int ilistendpos; 
    
string strname; 
    
while(*szTmp!='e'
    { 
        
if(!readstring(szTmp,ilistendpos,pNewDict->m_listObj)) 
          
break
        
if(m_plastObj->m_type !=enum_BEncodeType_String) 
          
break;          
        strname.assign(((CBEncodeString 
*)m_plastObj)->m_szData,((CBEncode 
String 
*)m_plastObj)->m_ilen); 
        szTmp
+=ilistendpos; 
        
if(*szTmp== 'i'
        { 
          
if(!readint(szTmp,ilistendpos,pNewDict->m_listObj)) 
            
break;//遇到任何错误都终止整个解析 
          szTmp+=ilistendpos; 
        } 
        
else if(*szTmp== 'l'
        { 
          
if(!readlist(szTmp,ilistendpos,pNewDict->m_listObj)) 
            
break
          szTmp
+=ilistendpos; 
        } 
        
else if(*szTmp== 'd'
        { 
          
if(!readdict(szTmp,ilistendpos,pNewDict->m_listObj)) 
            
break
          szTmp
+=ilistendpos; 
        } 
        
else          
        { 
          
if(!readstring(szTmp,ilistendpos,pNewDict->m_listObj)) 
            
break
          szTmp
+=ilistendpos; 
        } 
        pNewDict
->m_mapObj.insert(pair(strname 
,m_plastObj));          
    }    
    
if(*szTmp!='e'||m_plastObj->m_error != enm_BEncodeErr_noerr) 
        pNewDict
->m_error = enm_BEncodeErr_errDict; 
    
else 
        szTmp
++
  } 
  
else 
    pNewDict
->m_error = enm_BEncodeErr_errDict; 
  listObj.push_back(pNewDict); 
  iendpos 
= szTmp-szCurPos; 
  m_plastObj 
= pNewDict;    
  m_plastObj
->ilen = iendpos; 
  
return pNewDict->m_error == enm_BEncodeErr_noerr?true:false
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值