https://github.com/zytc2009/BigTeam_learning
分类:
2010-11-06 16:18:44
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;
}
peer.c和btget.c模块因为长度实在很长,加之我实在没什么时间写文章了,所以把我作了注释的源代码上传上来就算了.
解压密码: writer15
|