Your Ad Here
首页 | 编程语言 | 网站建设 | 游戏天堂 | 冲浪宝典 | 网络安全 | 操作系统 | 软件时空 | 硬件指南 | 病毒相关 | IT 认证
软讯网络 > 编程语言 > C/C++ > 一个人的战争 : 一个BT Client的开发笔记 (1)
【标  题】:一个人的战争 : 一个BT Client的开发笔记 (1)
【关键字】:BT,Client
【来  源】:http://blog.csdn.net/SolidusSnake/archive/2006/09/05/1177432.aspx

一个人的战争 : 一个BT Client的开发笔记 (1)

Your Ad Here

        自学C++一年有余,一直想自己开发个什么东西,终于在今年7月份决定写个BT的客户端吧,恩,说干就干,于是开始了这次痛苦的旅程,越深入到各个细节当中越觉得自己可能完不成这个东西了,故决定开始写Blog激励自己一下,也希望能把一个编程新手遇到的各种困难都记录下来,供他人借鉴,也便于自己日后的查寻. 我这人比较罗嗦,可能整个文档中间会夹杂一些个人感悟,期望哪位不幸读到的朋友谅解. 有对P2P一类软件感兴趣的朋友可以加我qq: 2070341一起聊聊, 自己写东西实在是很孤独.

说干就干,说写就写,先从种子文件开始.

(1):  Bencoding格式

         这个东西是所有相关资源的来源,所以必须先搞定. 下面简单阐述一下,大概格式,有兴趣的网友可以到http://wiki.theory.org/BitTorrentSpecification 参照标准.

     Bencoding采用的是一种字典格式,其中包括四种数据类型,string, int, list和dictionary.其中list和dict都是容器,能包含这四种类型的任意一种,dict的key当然就是string,注意,学过设计模式的朋友想到什么了? 对Composite!

string      4:abcd
int           i1234e
list          l4:abcdi1234ee    一个装有一个string和一个int的list
dict         d3:aaal4:abcdi1234eee 一个装有一条记录的字典,key为aaa,value是个list

下面是一段解析bencoding程序的源码,因为整个bencoding文件就是一个dict,所以最后生成的是个dict,然后再用具体的类来解析这个dict得到相应的内容,请看:


/***************************************************************************************/


enum DataType { STRING_TYPE, INTEGER_TYPE, LIST_TYPE, DICT_TYPE };


class TypeBase
{
private:
        DataType        obj_type;
public:
        TypeBase(
const DataType &data_type) : obj_type(data_type) {}
        
virtual ~TypeBase() {}
public:
        DataType type() 
const return obj_type; }
        
virtual void clear() = 0;
        
}
;


class StringType : public TypeBase
{
private:
        
//std::string        m_str;
        std::vector<char>    m_str;
public:
        StringType();
        StringType(
const StringType& other);
        StringType(
const std::vector<char>& str);
        StringType(
const std::string &str);
        
~StringType(){}
        StringType
& operator= (const StringType &other);
        StringType
& operator= (const std::vector<char> &str);
public:
        
void assign(const std::vector<char> &str);
        size_t size() 
const return m_str.size(); }
        std::
string get_str() const return std::string(m_str.begin(), m_str.end()); }
        
void get_str(std::vector<char> &str) { str = m_str; }
public:
        
virtual void clear() { m_str.clear(); };
        
}
;
class IntegerType : public TypeBase
{
private:
        t_u_int64            m_int;
public:
        IntegerType();
        IntegerType
& operator=(const t_u_int64 n);
        IntegerType(
const IntegerType& other);
        IntegerType(
const t_u_int64 n);
        IntegerType
& operator=(const IntegerType &other);
        
~IntegerType(){}
        
public:
        t_u_int64 get_int()
const return m_int; }
        
virtual void clear() {}
}
;



class ListType : public TypeBase
{
public:
        typedef std::list
<TypeBase*>::iterator            ThisIterator;
        typedef std::list
<TypeBase*>::const_iterator    C_Iterator;
private:
        std::list
<TypeBase*>    m_list_data;
private:
        ListType(
const ListType& other);
        ListType
& operator= (const ListType & other);
public:
        ListType();
        
~ListType();
public:
        
void insert(TypeBase *ptype); 
        size_t size() 
return m_list_data.size(); }
        ThisIterator begin() 
return m_list_data.begin(); }
        ThisIterator end()   
return m_list_data.end(); }
        C_Iterator const_begin() 
const return m_list_data.begin(); }
        C_Iterator const_end() 
const return m_list_data.end(); }
        
virtual void clear();
}
;



class DictType : public TypeBase
{
public:
        typedef std::map
<StringType*, TypeBase*>::iterator                ThisIterator;
        typedef std::map
<StringType*, TypeBase*>::const_iterator        C_Iterator;
private:
        std::map
<StringType*, TypeBase*> m_map_data;
private:
        DictType(
const DictType&);
        DictType
& operator=(const DictType&);
public:
        DictType() : TypeBase(DICT_TYPE) 
{}
        
~DictType() { clear(); }
public:
        TypeBase
* get_value( const std::string& key);
        
bool set_value(StringType* pstr_bt, TypeBase* ptype_bt);
        size_t size() 
return m_map_data.size(); }
        C_Iterator const_begin() 
const return m_map_data.begin(); }
        C_Iterator const_end() 
const return m_map_data.end(); }
        ThisIterator begin() 
return m_map_data.begin(); }
        ThisIterator end() 
return m_map_data.end(); }
public:
        
virtual void clear();
        
}
;

/***************************************************************************************/

 


四种类型都派生自一个TypeBase基类, 故ListType和DictType只需装入一个TypeBase*就OK了,Runtime识别的时候用基类的type()const函数返回的DataType 来识别,我这里并没有给基类提供一个更宽大的接口,没必要.

下面是解码类 BExtractor

 


class BExtractor  : private NonCopyable
{
private:
        
private:
        std::vector
<t_byte>        bfile;
public:
        size_t analyzer(size_t beg_pos, TypeBase 
*&pbase);//供给read_list和read_dict递归提取类型
        size_t read_string(size_t beg_pos, StringType &str_bt);
        
//从指定位置开始位置(基于0)
        
//将内容加入到一个ListType中,内部调用analyzer函数, 会导致递归调用
        
//任何错误都将导致返回 0,直接解析失败
        
//如无错误,则返回读取的内容长度,
        size_t read_int(size_t beg_pos, IntegerType &int_bt);
        
        size_t read_list(size_t beg_pos, ListType 
&list_bt);    
        size_t read_dict(size_t beg_pos, DictType 
&dict_bt);
        
//根据执行起始位置(此起始位置
        size_t locate_key(size_t beg_pos, const std::string &key);
public:
         
//接受一段元数据作分析 当然是bencoding file, 如果未搜索到第一个d,则返回false;
        bool set_content(const std::vector<t_byte> &meta); 
        size_t get_content(size_t b, size_t e, std::vector
<t_byte> &content); //根据执行位置提取一段元数据
        void clear() { bfile.clear(); }
public:
        BExtractor()
{};
        
~BExtractor(){};
}
;

 


        这个类负责抽取Bencoding文件为一个巨型的DictType,当然,也可以根据需要再合适的位置进行相应的操作,例如后期的tracker request时候解码tcp tracker返回的信息,这是后话,暂且不提.大概知道是干什么的就成了.下面是对生成的这个DICT类型的信息提取,使用函数


bool seed_decoder(const std::string &fname, SeedInfo &seed_info);

 

SeedInfo结构为:

  


struct FileInfo
{
        t_u_int64                        length;
        std::
string                        md5sum;
        std::list
<std::string>            path;
public:
        FileInfo();
        
~FileInfo() {}
        FileInfo(
const FileInfo& other);
        FileInfo
& operator=(const FileInfo &other);
public:
        
void clear();
        
}
;

struct SeedInfo
{
        
bool                            is_multi_files;
        std::vector
<t_u_int8>            info_hash;
        
//std::string                        announce;                //tracker服务器的URL(字符串)
        std::list<std::string>            anounce_list;            //备用tracker服务器列表(列表)
        t_u_int64                        creation_date;     
           //种子创建的时间,Unix标准时间格式,从1970 1月1日 00:00:00到创建时间的秒数(整数)
        std::string                        comment;                //备注(字符串)
        std::string                        created_by;                //创建人或创建程序的信息(字符串)
        std::string                        name;                    //多文件时使用,name:最上层的目录名字(字符串)
        t_u_int64                        piece_lengh;            //每个块的大小,单位字节(整数)
        std::vector<char>                pieces;                    //每个块的20个字节的SHA1 Hash的值(二进制格式)
        std::string                        publisher;
        std::
string                        publisher_url;
        std::list
<FileInfo>                files;                    //多文件时使用;
        size_t                            pieces_num;
//utf8扩展
        bool                            is_utf8;
        std::
string                        publisher_url_utf8;
        std::
string                        publisher_utf8;
        std::
string                        name_utf8;
        std::
string                        comment_utf8;
        
private:
        
void copy(const SeedInfo &other);
public:
        SeedInfo();
        SeedInfo(
const SeedInfo& other);
        SeedInfo
& operator= (const SeedInfo &other);
        
~SeedInfo() {}
        
void clear();
}
;

 


        这个函数的内部实现相当混乱,我不作过分的叙述了,日后要改的,这里有必要提一下的是 : std::vector<t_u_int8>   info_hash;  //这个数据成员,

        它是由整个Bencoding格式文件的字典中的"Info" 这个key所对应的dict类型的160位sha1 hash值, 这个有必要说一下,不太清楚的请参阅相关资料,这东西最好从bit的角度理解,故此,info_hash这个数据成员的.size()为20,   typedef unsigned char  t_u_int8;

        这个几个类都被我放到了头文件bencoding_type.h头文件中了.由于本人软件的设计能力有限,所以整个架构比较乱,后面写了一个包括网络,异步I/O,完成端口,code page转换等庞大的lib库,相互的耦合度的比较大, 这个相对来说还是最独立的,所以源码一概不贴,有需要的朋友请加我QQ.

        Bencoding解码先说到这,明天有空将贴tracker查寻的源码,我尽量保证每天写一篇笔记以记录自己的工作进度!

  

远程执行CMD命令部分代码:【上一篇】
恶梦:【下一篇】
【相关文章】
  • [原创] Web表现层的Client端设计模式探讨
  • Great!The Atlas client library has compressed in release mode.
  • Linux下PF_PACKET的使用,RARP的server和client程序
  • WebTestSuite
  • LINUX 命令行下BT的安装
  • radiusclient-0.3.2 中radacct的用法
  • Developing WebSphere MQ Client Applications in C++
  • 限制BT方法大全
  • SqlDbType 与 .Net 数据类型对照表
  • How To Use WordBasic Functions in an MFC Automation Client for Word 97, Word 2000, Word 2002, or Wor...
  • 【随机文章】
  • 用API关闭或打开显示器
  • 信息安全管理体系的实施过程(2)
  • 我改的第一个ajax程序
  • Dojo使用入门之一
  • Director MX 2004教程--我的第一个作品
  • 如何使用VS2005的WebTest对webservice进行数据源绑定测试
  • 问题,如何把上传文件的浏览按钮换成其他样式 或者图片
  • 如何用JavaScript识别Netscape 6 浏览器
  • 使用Sql生成测试数据
  • 系统进程让你明明白白(比较全面的)(转)
  • 【相关评论】
    没有相关评论
    【发表评论】
    姓名:
    邮件:
    随机码*
    评论*
          
    |  首 页  |  版权声明  |  联系我们   |  网站地图  |
    CopyRight © 2004-2007 bbb软讯网络 All Rigths Reserved.