教程:用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是否準備好,以及接受文件分片。敬請關注


分享到:


相關文章: