golang 时间戳_教程:用golang从零开始手写一个bt下载客户端(2) - Go语言中文社区

golang 时间戳_教程:用golang从零开始手写一个bt下载客户端(2)


背景

在上篇中,我们介绍了BT下载的原理,并通过示例搭建了一个p2p网络,了解了BT下载的原理和流程,从这篇文章将开始我们将用golang从零开始手写一个bt下载客户端。在开始动手之前,我们需要得到一个.torrent文件并解析它。

.torrent文件结构

这是一个文本文件,包含了要我们开始下载的全部信息:要分享的文件信息和连接到tracker服务器的信息。它使用bencode编码,就像这样:

d8:announce41:http://bttracker.debian.org:6969/announce7:comment35:"Debian CD from cdimage.debian.org"13:creation datei1573903810e9:httpseedsl145:https://cdimage.debian.org/cdimage/release/10.2.0//srv/cdbuilder.debian.org/dst/deb-cd/weekly-builds/amd64/iso-cd/debian-10.2.0-amd64-netinst.iso145:https://cdimage.debian.org/cdimage/archive/10.2.0//srv/cdbuilder.debian.org/dst/deb-cd/weekly-builds/amd64/iso-cd/debian-10.2.0-amd64-netinst.isoe4:infod6:lengthi351272960e4:name31:debian-10.2.0-amd64-netinst.iso12:piece lengthi262144e6:pieces26800:�����PS�^�� (binary blob of the hashes of each piece)ee

bencode

上面那一堆“乱码”是用一种叫做bencode(发音:bee-encode)的编码方式生成的信息,它不是人类直接可读的,我们需要把它解码才能使用,但它能够高效的编码二进制数据,并且很容易解析。它使用的数据结构和JSON大致相同,共包含4种数据结构:string,integer,list,dictionary。

  • string:用一个数字前缀加冒号表示长度如字符串spam表示为4:spam
  • integer:用i表示开始e表示结束,如数字7表示为i7e
  • list:用l表示开始e表示结束,如['spam',7]表示为l4:spami7ee
  • dictionary:用d表示开始e表示结束,如{spam:7}表示为d4:spami7ee

我们可以使用现成的工具bencode editor来读写.torrent文件

aeacec99e7621acdc43e986ef4dea972.png

bencode editor

在这个文件里,我们可以找出来tracker服务器地址,创建时间(用unix时间戳表示),文件名、大小以及文件的每个分片。

解析.torrent文件

实现一个bencode也许是很有趣的,但不是我们现在要关注的,我们将使用一个现成的库github.com/jackpal/bencode-go来完成。

package torrentfileimport ("bytes""crypto/sha1""fmt""os""github.com/jackpal/bencode-go")type TorrentFile struct {Announce    stringInfoHash    [20]bytePieceHashes [][20]bytePieceLength intLength      intName        string}type bencodeInfo struct {Pieces      string `bencode:"pieces"`PieceLength int    `bencode:"piece length"`Length      int    `bencode:"length"`Name        string `bencode:"name"`NameUtf8    string `bencode:"name.utf-8"`}type bencodeTorrent struct {Announce string      `bencode:"announce"`Info     bencodeInfo `bencode:"info"`}func Open(path string) (TorrentFile, error) {file, err := os.Open(path)if err != nil {return TorrentFile{}, err}defer file.Close()bto := bencodeTorrent{}err = bencode.Unmarshal(file, &bto)if err != nil {return TorrentFile{}, err}return bto.toTorrentFile()}func (bto *bencodeTorrent) toTorrentFile() (TorrentFile, error) {infoHash, err := bto.Info.hash()if err != nil {return TorrentFile{}, err}pieceHashes, err := bto.Info.splitPieceHashes()if err != nil {return TorrentFile{}, err}t := TorrentFile{Announce:    bto.Announce,InfoHash:    infoHash,PieceHashes: pieceHashes,PieceLength: bto.Info.PieceLength,Length:      bto.Info.Length,Name:        bto.Info.Name,}return t, nil}

为了保持结构的扁平化,我们把一个结构分成了几个,并使用一个工具函数来合并他们。

后面我们将从tracker获取到peers的信息,敬请关注。

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_39900437/article/details/110663603
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-05-15 20:51:58
  • 阅读 ( 1023 )
  • 分类:Go

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢