背景
上篇文章我们介绍了如何从traker服务器下载peers的信息,并用golang实现了这个http请求,解析出来每个peer对应的ip和端口。接下来我们将要和其他peer建立连接,第一步就是握手。
流程
要完成握手,需要以下几步:
- 发起一个tcp连接
- 完成一个双向握手,“你好?”“你好”
- 交换消息并下载分片
验证消息
- 首先确定该peer使用的协议是Bittorrent protocol协议
- 还要理解和返回消息
- 并且存在我们要下载的文件分片,知道我们需要什么
握手协议
好的握手要眼神看着对方并紧握对方,BitTorrent protocol包含以下5个部分:
- 协议ID的程度,通常为19(16进制为0x13)
- 协议ID的字符串pstr通常为“BitTorrent protocol”
- 8字节保留位,全设置为0,可以把某些位设置为1表示支持默写扩展
- infohash,我们早先计算出来的infohash
- 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是否准备好,以及接受文件分片。敬请关注
閱讀更多 愛碼士 的文章