Linux下BT种子解析模块

Linux下BT种子解析模块
Linux下BT种子解析模块

Linux下BT种子解析模块

一.概要介绍

1.BT协议的介绍

BitTorrent是一个文件分发协议,每个下载者在下载的同时不断向其他下载者上传已经下载的数据。而在FTP,HTTP协议中,每个下载者从FTP,或HTTP服务器处下载自己所需要的文件,各个下载者之间没有交互。当非常多的用户同时访问和下载服务器上的文件时,由于服务器的处理能力以及带宽限制,下载速度会急剧下降,有的用户根本访问不了服务器。BT协议与FTP协议不同,它的特点是下载的人越多下载的速度越快,其原因在于每个下载者将已下载的数据提供给其他下载者下载,它充分利用了用户的上载带宽。

而Web服务器上保存着种子文件,下载者使用网络浏览器从Web服务器上下载种子文件。种子文件,又成为元原文件或者metafile,它保存了共享文件的一些信息,如共享文档的文件名,文件大小,Tracker服务器的地址。种子文件通常很小,一般1G大小的共享文件,其种子文件不足100KB,种子文件以torrent为后缀。BT客户端下载一个共享文件的开始过程,往就是客户端首先解析种子文件,获取待下载文件的一些信息,其中包括Tracker服务器的地址,然后根据得到的地址连接Tracker服务器,获得peer端信息,最后再在peer之间传送消息和数据。

共享文件在逻辑上被划分为大小相同的块,成为piece,每个piece的大小通常称为256K。对于共享文件,文件的第1字节到第256K字节为第一个piece,第256K+1字节到512K 字节被称为第二个piece,依此类推。种子文件中包含有每个piece的hash值。BT协议规定使用Sha1算法对每个piece生成20字节的hash值,作为每个piece的指纹。

2.B编码的介绍

种子文件和Tracker的返回信息都是经过B编码的,要解析和处理种子文件以及Tracker 的返回值,首先要熟悉B编码的规则。B编码中有4中类型:字符串,整型,列表和字典。字符串的编码格式为:<字符串的长度>:<字符串>,其中<>括号中的内容为必须的,例如有一个字符串spam,则经过B编码后为4:spam。

整型的编码格式为:i<十进制的整型>e,则B编码中的整数是以i作为起始符,以e作为终结符。例如,整数3,经过B编码后为i3e。

列表的编码格式为:l<任何合法的类型>e,列表以l为起始符,以e为终结符,中间可以为任何合法的经过B编码的类型。例如,列表l4:spam4:eggse表示两个字符串,一个是spam,另一个是eggs。

字典的编码格式为:d<关键字><值>e,字典以d为起始符,以e为终结符,关键字是一个经过B编码的字符串,值可以是任何合法的B编码类型,在d和e之间可以出现多个关键字和值对。例如,d4:spaml3:aaa3:bbbee,它是一个字典,该字典的关键字是spam,值是一个列表,列表中有两个字符串aaa和bbb。

3.BT种子结构的介绍

种子文件包含了提供共享的文件的一些信息,它以.torrent为后缀名,种子文件也被称为元信息文件或metafile,它是经过B编码的。种子文件事实上就是一个B编码的字典,它包含有以下关键字:

announce:tracker服务器的URL(字符串)

announce-list(可选):备用tracker服务器列表(列表)

creation date(可选):种子创建的时间,Unix标准时间格式,从1970 1月1日00:00:00到创建时间的秒数(整数)

comment(可选):备注(字符串)

created by(可选):创建人或创建程序的信息(字符串)

info:一个字典结构,包含文件的主要信息,为分二种情况:单文件结构或多文件结构单文件结构如下:

length:文件长度,单位字节(整数)

md5sum(可选):长32个字符的文件的MD5校验和,BT不使用这个值,只是为了兼容一些程序所保留!(字符串)

name:文件名(字符串)

piece length:每个块的大小,单位字节(整数)

pieces:每个块的20个字节的SHA1 Hash的值(二进制格式)

多文件结构如下:

files:一个字典结构

length:文件长度,单位字节(整数)

md5sum(可选):同单文件结构中相同

path:文件的路径和名字,是一个列表结构,如\test\test.txt 列表为l4:test8test.txte name:最上层的目录名字(字符串)

piece length:同单文件结构中相同

pieces:同单文件结构中相同

4.GNU make工具的介绍

Linux环境下的大型项目开发中,通常把整个系统划分为若干模块,每个模块完成某一相对独立的功能,各个模块相互作用以构成一个完整的系统。对于这样的一个软件系统,是不可能只用一条或者几条gcc命令就可以编译生成可执行程序的。而且模块通常要经历几次修改,每次修改后如果都有人工输入命令以完成编译,这样子既效率低下又容易出错。

在Linux中,有一个用来维护程序模块关系和生成可执行程序的工具-make。它可以根据程序模块的修改情况重新编译链接生成中间代码或最终的可执行程序。执行make命令,需要一个名为“makefile”或者“Makefile”的文本文件,这个文件定义了整个项目的编译规则。它定义了模块间的依赖关系,指定文件的编译顺序,以及编译所使用的命令,有了make命令和Makefile文件,整个项目的源程序文件可以自动编译,极大的提高了软件开发的效率。

二.模块的设计与实现

根据需求,在模块中实现查找特定关键字功能的函数find_keyword(keyword,position),其中keyword为待查的关键字,而position为一返回参数,返回查找到的关键字所在位置。为了提高查找效率,将种子文件的内容读入内存,直接在内存中进行字符串匹配。

函数read_announce_list()获取Tracker地址,并将获取的地址保存到全局变量announce_list_head所指向的结构体中。只需在种子文件内容所在的内存中查找关键字“8:announce”即可,找到之后接下来的字符内容即是Tracker的URL地址,将相应的内容复制进全局变量即可。

在判断是多文件还是单文件时,关键是查找关键字“5:files”,如果在种子文件中找到相应的内容,即说明为多文件种子,否则为单文件。

同理,在得出单个piece长度,以及获取每个piece的hash值,获取待下载文件的文件名

及大小,以及获取文件目录时,都是采用先定位各个关键字,如“12:piece length”,“6:pieces”,“4:name”等等,然后再在之后抽取相应的内容,保存在相应的全局变量中即可。

在提取种子文件中info_hash值时,由于是由关键字“4:info”对应的值来计算info_hash,该关键字对应的值是一个B编码的字典,问题的关键在于找到与“4:info”之后‘d’对应的‘e’。此时可以考虑在括号匹配问题中的解决方案,即用堆栈来记录相应的位置,然后一一匹配,直到匹配完成。

由于该模块只是整个项目程序中的一个功能部分,因此可以考虑到后面的模块,需要为每一个主机设置一个随机唯一的id,此时只要调用随机生成算法,生成一个随机数即可。再在模块中增添相应的释放动态申请的内存的函数。

在编写makefile文件时,由于只需生成最后的可执行文件,因而中间代码之类的全部省略,于是可以简短的将makefile文件写为:

main:parse_torrent.c main.c sha1.c

gcc -o main parse_torrent.c main.c sha1.c

其中parse_torrent.c main.c sha1.c为c代码原文件,生成的main文件为最后的可执行文件。

三.模块达到的功能

由于该模块只是BT下载软件项目中的一个辅助模块,因此里面没有太多的功能,最后完成的效果是可以下载互联网上的种子,然后将项目中某些后续需要的内容解析出来,打印出来即可。我在互联网上下载的种子文件为“铁面无私.torrent”,在Linux下调用该模块解析该种子之后打印相应的内容为:

jiangrains@linux-hrx6:~/Desktop/course> ./main

输入种子文件名:铁面无私.torrent

该种子的tracker的url地址为:https://www.360docs.net/doc/5c14240881.html,:8000/announce

单个piece的长度为(一般为256K):524288B

该文件为多文件种子,其目录名为:????????????

该目录下共有文件数为:9 个,如下:

文件1:

length:105394B

path:11.JPG

文件2:

length:79230B

path:22.JPG

文件3:

length:72105B

path:33.JPG

文件4:

length:644B

path:https://www.360docs.net/doc/5c14240881.html,@?????????.html

文件5:

length:683B

path:https://www.360docs.net/doc/5c14240881.html,@?????????????.html

文件6:

length:738B

path:https://www.360docs.net/doc/5c14240881.html,@?????????????.html

文件7:

length:1796788764B

path:https://www.360docs.net/doc/5c14240881.html,@???????.rmvb

文件8:

length:657B

path:https://www.360docs.net/doc/5c14240881.html,@???????.html

文件9:

length:137216B

path:https://www.360docs.net/doc/5c14240881.html,@??????????(??????Ч).doc

总计文件大小为:1797185431B

该种子文件的info_hash 为:9b 32 f1 d3 de 8e a2 0e 55 4b 7d 66 58 df 1c 3d e0 c5 3d e6

随机得到的peer id 为:-TT1000- 859096440

jiangrains@linux-hrx6:~/Desktop/course>

四.总结

在调试一个比较大型的项目程序时,由于代码多并且程序功能分配不清楚的话,会很难知道怎么下手。这个时候就要考虑到程序模块化的重要,把一些相对功能独立的程序段放在一个独立的模块中,如果程序出错,就可以按照模块,一个一个调试开来,这样子更容易找出程序冲存在的bug,并且也可以在开始编写程序的过程中,不断调试程序,直到该模块能够正常工作时,或许才是开始进行下一个模块的开始时。在划分模块时,也要考虑模块的复杂度,有时候模块中的函数不能太长,按照人的习惯,一般一个函数的最适合代码行数不超过200行。如果超出时,就要考虑是否需要再行划分为更细的模块,这样子更方面代码的调试,以及后续维护工作的进行。

在写程序时争取把程序写得有条理有层次,多写几个函数,这样调起来也方便只要保证每个函数正确就可以逐步缩小范围。

而在Linux下进行程序设计时,更应该考虑互联网的作用,当有问题时,不断地在网上,论坛提问,你所获得的解答往往会把你最想知道的告诉你,并且有时候你的某一个不经意的提问或许也能带给更多的人更多的想法,其中就不乏闪光之处。

阅读经典书籍往往带给人们的是通向目的地的捷径,而在Linux下进行程序设计时,stevens经典的3部unix编程系列书籍,带给我很多值得细细品味与深思的东西,而在体会先生著作之时,自身的编程能力,编程艺术也在不断提高,提升。

五.参考文献

1.W.Richard Stevens, Stephen A.Rago:UNIX环境高级编程(apue)

2.Eric S.Raymond:UNIX编程艺术

3.童永清:Linux C编程实战

4.William Stallings:操作系统-精髓与设计原理

5.W.Richard Stevens:UNIX网络编程(unp)

相关主题
相关文档
最新文档