libbt研究笔记-1
作者:writer15 mail:writer15(at)163.com
转载请注明原作者名称,联系方法和出处
目的 -------------------------------------------------------------------------------- 在2006年9月开始,我就计划用C++开发一套夸平台、功能齐全、高性能的BT库。在开始的时候我除了对SOCKET编程有比较深的了解外,对BT协议什么的一点不懂。到了2007年的3月,都没有开发出像样的成品。失败原因主要是太多功能综合在一起并且要实现夸平台已经是一个高难度的挑战,加上BT协议真的比较复杂,所以还没成功。我知道这个时候继续闭门造车是不会成功的,所以我转向研究他人的BT项目。最后在sourceforge.net找到了这个libbt库,研究了一翻,这系列的文章就是我的分析结果。
关于libbt -------------------------------------------------------------------------------- 主页:http://sourceforge.net/projects/libbt/
libbt是一个用C语言开发的BT库,实现在功能不多(没有DHT,没文件选择下载,没磁盘缓冲,没UPnP……),用户界面更是“古老”的CUI。但这些都不是问题,我要研究的主要是其网络IO模式和一些BT内部的算法(如choke算法,piece选择算法,还有文件如何组织及保存等)
概论 -------------------------------------------------------------------------------- libbt的源码在src目录下,包含文件在include目录下。基本上是一个文件一个模块,下面从总体上来看看各各模块的功能吧。 benc.c bitset.c 用于操作比特位串,如BT协议中的btifield block.c btcheck.c 一个小工具,make后成为btcheck可执行文件,具体作用未明。 bterror.c 定义了小量的自定义错误代码和相应的 错误字符串信息 btget.c 主程序,各模块在这个文件中组合起来,make后成为btget可执行文件 btlist.c 另个一个小工具,make后成为btlist可执行文件,具体作用未明。 bts.c context.c 这个模块提供了一些全局信息处理的函数,还有修改socket的poll事件通知函数, 最后还有tracker通信的一些函数。 peer.c BT通信协议的实现模块 random.c 仅仅提供2个函数,randomid(...)用于随机返回一个peerid; rnd(max)函数是随机返回一个不大于max的整数; segmenter.c torrent中的数据是piece为单位的,这个模块就是提供相关的piece存取函数。 strbuf.c 内存缓冲模块,实现了一个自动扩展的动态缓冲机制。 stream.c sokcet的封装模块,除了封装了recv/send外,还实现接收/发送缓冲机制。 types.c util.c 一些工具类函数,其中封装了一些内存分配函数(malloc, realloc, free等)
util.c模块 -------------------------------------------------------------------------------- 这个模块封装资源分配函数,目的有2点,一是集中在封装函数里检测返回值,如果失败,直接结束进程;二是如果将来要使用内存池,直接修改这几个函数就可以了。
/* malloc, calloc, realloc, free函数的封装函数 */ void *btmalloc( size_t size); void *btcalloc( size_t nmemb, size_t size); void *btrealloc( void *buf, size_t size); void btfree( void *buf);
/* C函数strerror的封装,但同时也自定义了一些错误码(在bterror.h中),至于两者有没重复还不清楚。*/ char *bts_strerror( int err);
/* fprintf( stderr, "%s: [%d] %s\n", msg, err, bts_strerror(err)); */ void bts_perror( int err, char *msg);
/* 输出输入的信息,并且调用abort()函数,终止进程。 */ int die( char *file, int line, char *msg, int err);
/* 创建文件所需要的目录,因为open()函数不会自动创建不存在的目录。 */ int openPath( char *path, int flags);
/* 用输入的参数打开一个文件 */ int cacheopen( char *path, int flags, int mode);
/* 关闭所有打开的文件 */ void cacheclose( void);
/* 将digest中的每个字节转换成%??形式输出到buf中。 */ void hexencode (const unsigned char *digest, int len, char *buf, int buflen);
/* 将buf中%??形式的数据输入成原始比特位,放到digest中。 */ int hexdecode (unsigned char *digest, int len, const char *buf, int buflen);
总结:封装资源分配函数的做法值得学习,当然前提是你用C作为开发语言。还有值得注意的是在源代码中会看到一些实现跨平台的宏,但我曾经试过在VS2005中编译这个项目但不成功,而且后来查看了源码发现跨平台还没有实现的。
strbuf.c模块 -------------------------------------------------------------------------------- strbuf.c模块比较简单,其中的所有的函数都围绕着一个结构进行。
struct kStringBuffer { int bufsize; //缓冲的大小
int cpos; //已经使用的缓冲大小
char *buf; //缓冲区地址
};
下面简单地说一说每个函数的用法(英文好的朋友,可以直接看strbuf.h,里面有详细的函数说明)
/* 创建一个kStringBuffer。当参数sb非NULL时,将它初始化并返回它;否则malloc一个新的。*/ kStringBuffer* kStringBuffer_create( kStringBuffer *sb);
/* 释放sb的缓冲,并且将结构中的全部成员置0 */ void kStringBuffer_finit( kStringBuffer *sb);
/* 清空sb中的数据 */ void sbclear( kStringBuffer *sb);
/* 添加字符c到sb的缓冲中 */ int sbputc( kStringBuffer *sb, char c);
/* 添加一个C字符串到sb的缓冲中 */ int sbstrcat( kStringBuffer *sb, char *str);
/* 添加一个长度为len的内存块到sb的缓冲中 */ int sbcat( kStringBuffer *sb, char *str, int len);
/* 删除sb缓冲中的首first_cahr个字符*/ int sbtail( kStringBuffer *sb, int first_char);
/* 在sb的缓冲中查找ch的第一次出现的位置 */ int sbindex( kStringBuffer *sb, int ch);
总结:短小但非常有用的一个模块,socket的接收和发送缓冲就是用它作为基础的。
|