教程:用golang从零开始手写一个bt下载客户端(4)

背景

上篇文章我们介绍了如何从traker服务器下载peers的信息,并用golang实现了这个http请求,解析出来每个peer对应的ip和端口。接下来我们将要和其他peer建立连接,第一步就是握手。

流程

要完成握手,需要以下几步:

  1. 发起一个tcp连接
  2. 完成一个双向握手,“你好?”“你好”
  3. 交换消息并下载分片

验证消息

  • 首先确定该peer使用的协议是Bittorrent protocol协议
  • 还要理解和返回消息
  • 并且存在我们要下载的文件分片,知道我们需要什么


教程:用golang从零开始手写一个bt下载客户端(4)

握手

握手协议

好的握手要眼神看着对方并紧握对方,BitTorrent protocol包含以下5个部分:

  1. 协议ID的程度,通常为19(16进制为0x13)
  2. 协议ID的字符串pstr通常为“BitTorrent protocol”
  3. 8字节保留位,全设置为0,可以把某些位设置为1表示支持默写扩展
  4. infohash,我们早先计算出来的infohash
  5. peer id,我们自己的客户端的peerid

组合起来就是:

<code>\\\\x13BitTorrent protocol\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x86\\\\xd4\\\\xc8\\\\x00\\\\x24\\\\xa4\\\\x69\\\\xbe\\\\x4c\\\\x50\\\\xbc\\\\x5a\\\\x10\\\\x2c\\\\xf7\\\\x17\\\\x80\\\\x31\\\\x00\\\\x74-TR2940-k8hj0wgej6ch/<code>

发送握手消息之后,我们将会收到一个相同格式的回复,返回单infohash必须和发送的一致,证明是同一个文件,如果都验证通过了,就继续,否则就断开这个连接。

代码实现

<code>type Handshake struct {
Pstr string
InfoHash [20]byte
PeerID [20]byte
}


// 序列化一个握手信息
func (h *Handshake) Serialize() []byte {
buf := make([]byte, len(h.Pstr)+49)
buf[0] = byte(len(h.Pstr))
curr := 1
curr += copy(buf[curr:], h.Pstr)
curr += copy(buf[curr:], make([]byte, 8)) // 8 reserved bytes
curr += copy(buf[curr:], h.InfoHash[:])
curr += copy(buf[curr:], h.PeerID[:])
return buf
}

// 解析返回的握手信息
func Read(r io.Reader) (*Handshake, error) {
// Do Serialize(), but backwards
// ...
}/<code>

好,现在我们已经和远程peers建立了连接,并且完成了握手,接下来就需要向peer发送消息,用以确定peer是否准备好,以及接受文件分片。敬请关注


分享到:


相關文章: