Chinaunix首页 | 论坛 | 博客
  • 博客访问: 164777
  • 博文数量: 36
  • 博客积分: 1466
  • 博客等级: 上尉
  • 技术积分: 380
  • 用 户 组: 普通用户
  • 注册时间: 2007-04-17 17:43
文章分类

全部博文(36)

分类: 系统运维

2007-05-02 19:41:03

libbt研究笔记-1

作者:writer15     mail:writer15(at)163.com
转载请注明原作者名称,联系方法和出处

bts.c模块 /* 2007-4-12 7:48下午 */
--------------------------------------------------------------------------------
#2天没写过文档了,原因是不知怎么表达接下来的几个模块,还有自己的一些事也很烦恼。
bts模块抽象出一套数据流的接口,通过这套接口,你可以对内存流,文件流进行操作,而且不用理会其种类和来源。


先来看看btStream结构

typedef enum { BTS_INPUT, BTS_OUTPUT, BTS_FREE } btsIo; //BTS_FREE未发现有引用的地方


struct btStream;
typedef struct btStream {
    int type; //eq BTFILESTREAM or BTSTRSTREAM

    btsIo iodir;
    int (*read)(struct btStream* bts, char *buf, int len);
    int (*write)(struct btStream* bts, char *buf, int len);
    int (*peek)(struct btStream* bts);
    int (*rewind)(struct btStream* bts, btsIo iodir);
    void (*destroy)(struct btStream* bts);
} btStream;

struct btstrbuf {
    char *buf;
    int len;
};

一个btStream实例就代表一个数据流对象。 type字段代表是流的类型,libbt中只有文件流和内存流2种。iodir字段到现在我也不太明白有什么用。之后就是5个函数指针,当流的类型不同的,它们指向不同的函数。 比如文件流,这5个指针就指向操作文件流的5个函数,内存流也一样。在创建流的时候指定类型和这5个函数,之后流接口函数就可以以相同的函数处理不同的流。

文件流和内存流的实现函数我就不多说了,看源码吧很简单。

下面说说这个模块输出的接口

/* 分配一块内存,创建数据流 */
btStream* bts_create_strstream() ;

/* 从一个文件描述符创建数据流 */
btStream* bts_create_filestream_fp( FILE *fp, btsIo iodir) ;

/* 打开指定的文件创建数据流 */
btStream* bts_create_filestream( char *fname, btsIo iodir) ;

/* 销毁数据流 */
void bts_destroy( btStream* bts);

/* 将数据流的指针重置到起点 */
int bts_rewind( btStream* bts, btsIo iodir);

/* 返回数据流的缓冲区,只支持内存流。文件流调用了会返回{NULL, 0} */
struct btstrbuf bts_get_buf( btStream *bts) ;

/* 从数据流中读取len个字节到buf中,如果数据流中的数据不够len个字节,返回1 */
int bts_read( btStream* bts, char *buf, int len) ;

/* 向数据流写入长度为len的buf */
int bts_write( btStream* bts, char *buf, int len) ;

/* 这个函数看看源码就明白。说到底就是向流写入size*nmemb字节的数据
size_t writebts( void *buf, size_t size, size_t nmemb, void* stream ) {
    btStream *bts=stream;
    int len=size*nmemb;
    if (bts_write(bts, buf, len) != 0) {
        return 0;
    }
    return len;
}
但是我有点觉得很不好的是,stream参数放在最后?和其它函数的风格都不同。
*/

size_t writebts( void *buf, size_t size, size_t nmemb, void* stream );

/* 返回数据流当前指针位置的数据,但并不移动指针。 */
int bts_peek( btStream* bts) ;

/* 向数据流输入格式化字符串 */
int bts_printf( btStream* bts, char *fmt, ...) ;

/*
 * bts_scanbreak
 * Read from an input stream and copy characters into 'buf' until hitting
 * a break character. If there are any characters that are not listed
 * in 'cset' then an error value is returned. Scanbreak is used to read
 * bEncoded integers.
 *
 * bts - I/O stream, must be an input stream
 * cset - List of allowed characters
 * bset - List of break characters
 * buf - Return value of data read from the stream
 * bufsz - Available space in the buffer
 *
 * return 1 on error, 0 on success
 */

int bts_scanbreak( btStream* bts, char *cset, char *bset, char *buf, int bufsz);



types.c模块
--------------------------------------------------------------------------------
这个模块的作用是提供保存bencode对象的容器和相关的操作函数。

照旧先看看相关结构

/* btObject只一个字段t标识容器类型,但实际上却不是容器(也就是说不保存任何数据)。*/
typedef enum btType { BT_STRING, BT_INTEGER, BT_LIST, BT_DICT } btType;
typedef struct btObject {
    btType t; //容器的类型

    /*... */
} btObject;

typedef struct btInteger {
    btObject parent;
    int allocated; //标识本结构分配哪(堆还是栈),以便destroy时处理

    _int64 ival;
} btInteger;

typedef struct btString {
    btObject parent;
    int allocated;
    int len;
    int bufsize;
    char *buf;
} btString;

typedef struct btList {
    btObject parent;
    int allocated;
    int len;
    int listsize;
    btObject **list;
} btList;

typedef struct btDict {
    btObject parent;
    int allocated;
    int len;
    int dictsize;
    btString *key;
    btObject **value;
} btDict;


//

typedef struct btDictIt {
    btDict *d;
    int idx;
} btDictIt;


下面再来看看模块的接口

/* Integer */
btInteger* btInteger_cast( btObject *o) ;
btInteger* btInteger_create( btInteger *i);
void btInteger_destroy( btInteger *i) ;

/* String */
btString* btString_cast( btObject *o) ;
btString* btString_create( btString *s) ;
btString* btString_create_str( btString *s, char *init) ;
void btString_destroy( btString *s) ;
char *btString_buf( btString *s) ;
int btString_len( btString *s) ;
int btString_cmp( btString *a, btString *b) ;
void btString_setbuf( btString *s, char *buf, int len) ;

/* List */
btList* btList_cast( btObject *o) ;
btList* btList_create( btList *buf) ;
void btList_destroy( btList *buf) ;
int btList_add( btList *_this, btObject *v) ;
btObject* btList_index( btList *_this, int idx) ;

/* Dict */
btDict* btDict_cast( btObject *o) ;
btDictIt* btDictIt_create( btDictIt *buf, btDict *d) ;
btDictIt* btDict_iterator( btDict *d) ;
int btDictIt_hasNext( btDictIt *i) ;
btString* btDictIt_first( btDictIt *i) ;
btString* btDictIt_next( btDictIt *i) ;
btDict* btDict_create( btDict *buf) ;
void btDict_destroy( btDict *_this) ;
int btDict_add( btDict *_this, btString* k, btObject* v) ;
btObject* btDict_find( btDict *_this, btString* k) ;

/* btObject */
int btObject_sizeof( btObject *b) ;
int btObject_destroy( btObject *b) ;
btObject* btObject_val( btObject *b, char *path);
void btObject_dump( int depth, btObject *o);

无非就是转换函数,创建/销毁函数,还有各自的专用函数,对动态类型语言有所了解的话很易明白。
最后要说明一下的是
btObject* btObject_val( btObject *b, char *path);
b一定要是list或者dict,path是以“/”分隔开的下标。比如有如果dict
d= {'a': 1, 'c': [1, 2, 3, 4], 'b': 2}
-------------------------------------
btObject* obj= btObject_val(b, 'c/2');
返回的obj将会为BT_INTEGER类型,值为3




benc.c模块
--------------------------------------------------------------------------------
benc.c模块的作用就是组合bts.c和types.c模块。之后你就可以从数据流中读取bencode或者写入bencode
* string */

/* all functions return 0 - success, 1 - error */
int benc_put_string( struct btStream* bts, btString *s) ;
int benc_get_string( struct btStream* bts, btString *s) ;

/* integer */
int benc_put_int( struct btStream *bts, btInteger *i) ;
int benc_get_int( struct btStream *bts, btInteger *i) ;

/* list */
int benc_put_list( struct btStream *bts, btList *a) ;
int benc_get_list( struct btStream *bts, btList *a) ;

/* dictionary */
int benc_put_dict( struct btStream *bts, btDict *d) ;
int benc_get_dict( struct btStream *bts, btDict *a) ;

/* object */
int benc_put_object( btStream *bts, btObject *o) ;
int benc_get_object( btStream *bts, btObject **o) ;

所有函数都可以从函数名看出函数功能,我也不多说。

如果大家还有什么问题,可以向我提出。

下面给出调用这3个模块的函数的例子

#include "config.h"

#include <openssl/sha.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "bts.h"
#include "types.h"
#include "benc.h"


int readTorrent(char *filename)
{
    int nRet = 0;
    btStream *bts = NULL;
    btObject *obj = NULL;

    btInteger *btint = NULL;

    //创见数据流

    bts = bts_create_filestream(filename, BTS_INPUT);
    if (bts == NULL)
        return 1;

    //从数据流读取bencode

    nRet = benc_get_object(bts, &obj);
    if (nRet != 0)
        return 2;
    
    //输出.torrent文件的info/piece length

    btint = BTINTEGER(btObject_val(obj, "info/piece length"));
    if (btint == 0)
        return 3;
    printf("\npiece length: %lld\n", btint->ival);
    
    //销毁

    btObject_destroy(obj);
    bts_destroy(bts);
    return 0;
}

int example1()
{
    /*** 变量定义 ***/
    char BTSTRING_TEST1[]= "test string1";
    char BTSTRING_TEST2[]= "test string2";
    char *p = NULL;
    int nRet = 0;
    btObject *btobj = NULL;
    btInteger *btint = NULL;
    btString *btstrA = NULL;
    btString *btstrB = NULL;
    btList *btlist = NULL;
    btDict *btdict = NULL;

    btString *key = NULL;
    btString *val = NULL;

    btDictIt *dictIt = NULL;


    /*** btInteger ***/
    printf("----------------------------------------------------------\n");
    btint = btInteger_create(NULL);
    btint->ival = 1234567890;
    printf("btint: %lld\n", btint->ival);

    /*** btString ***/
    //btstrA

    printf("----------------------------------------------------------\n");
    btstrA = btString_create_str(NULL, BTSTRING_TEST1);
    printf("btstrA = %s\n", btString_buf(btstrA));

    //btstrB

    p = btmalloc(strlen(BTSTRING_TEST2) + 10); //buffer will be free by btString_destroy()

    if (p == NULL)
        return 1;
    strcpy(p, BTSTRING_TEST2);

    btstrB = btString_create(NULL);
    btString_setbuf(btstrB, p, strlen(p));
    printf("btstrB = %s\n", btString_buf(btstrB));
    //cmp

    printf("btString_cmp = %d\n", btString_cmp(btstrA, btstrB));

    /*** btList ***/
    printf("----------------------------------------------------------\n");
    btlist = btList_create(NULL);
    btList_add(btlist, BTOBJECT(btint));
    btList_add(btlist, BTOBJECT(btstrA));
    btList_add(btlist, BTOBJECT(btstrB));

    btobj = btList_index(btlist, 0);
    btObject_dump(1, btobj);
    btobj = btList_index(btlist, 1);
    btObject_dump(1, btobj);
    btobj = btList_index(btlist, 2);
    btObject_dump(1, btobj);

    /*** btDict ***/
    printf("----------------------------------------------------------\n");
    btdict = btDict_create(NULL);
    key = btString_create_str(NULL, "test key 1");
    val = btString_create_str(NULL, "VALUE_of_dict");
    btDict_add(btdict, key, BTOBJECT(val));
    key = btString_create_str(NULL, "test key 2");
    btDict_add(btdict, key, BTOBJECT(btlist));

    btObject_dump(10, BTOBJECT(btdict));

    /*** btDictIt ***/
    printf("----------------------------------------------------------\n");
    dictIt = btDict_iterator(btdict); //返回dict的迭代器

    //输了所有key和value

    if (btDictIt_hasNext(dictIt))
    {
        key = btDictIt_first(dictIt);
        while (key != NULL)
        {
            printf("key>>>>>:");
            btObject_dump(10, BTOBJECT(key)); //print key

            btobj = btDict_find(btdict, key);
            printf("value>>>:");
            btObject_dump(10, btobj); //print value

            key = btDictIt_next(dictIt);
        }
    }

    btfree(dictIt);

//最值得注意的是btList_add()和btDict_add()将输入的btObject拥有权据为己有,所以只要销毁dict即可。

    btDict_destroy(btdict);
// btList_destroy(btlist);

// btString_destroy(btstrB);

// btString_destroy(btstrA);

// btInteger_destroy(btint);


    return 0;
}

int main( int argc, char **argv)
{
    int nRet = 0;

    printf("%s\n", "hello");

    nRet = readTorrent("/home/writer/119.torrent");
    printf("readTorrent: %d\n", nRet);

    nRet = example1();
    printf("example1: %d\n", nRet);

    return 0;
}


对所有外围模块都有所了解以后,接下来我将对libbt的几个核心模块进行分析。

阅读(1976) | 评论(1) | 转发(0) |
0

上一篇:libbt研究笔记-2

下一篇:libbt研究笔记-4

给主人留下些什么吧!~~

chinaunix网友2010-03-16 09:30:38

这是libbt研究笔记-1,而不是libbt研究笔记-3啊