Bittorrent 和套接字:如何处理多条消息?
Bittorrent and sockets: how to handle multiple messages?
我正在 python 中编写一个 bittorrent 客户端,并且一直在使用循环从使用 recv() 的对等套接字不断读取消息。
当我 运行 我的程序时,我在 wireshark 中查看我收到的比特流消息。很容易从消息的前 5 个字节中判断出您得到的是哪种消息,因为长度和消息 ID 已在此处指定。
我 运行 在处理接收包含多条消息的数据时遇到了一些问题。
我尝试通过编写这样的方法来解决它:
def handleMultiple(self, message, peer):
total_length = len(message)
parsed = 0
while parsed < total_length:
m_len, m_id = struct.unpack(">IB", message[parsed:parsed + 5])
m_total = m_len + 4
print(m_len, total_length, parsed, m_id, peer.made_handshake, peer.ip)
self.handleMessage(message[parsed:m_total + parsed], peer)
parsed += m_total
该函数只是将接收到的字节分解为其组成消息,并将其交给知道如何处理各个消息的消息处理程序。
问题是,当我从使用 recv() 收到的消息中打印出长度前缀和消息 ID 时,有时它看起来只是垃圾数字。
这真的是我第一次尝试使用套接字,所以我缺乏直觉,无法知道调用 recv() 时我真正得到了什么。我是否应该只对收到的前 5 个字节的数据调用 receive,然后进行一些检查以确保长度和 ID 有效,然后对消息的其余部分调用 recv()?
我应该如何处理一次传入的多条消息?
编辑:
我想提供一些我看到的结果图片,看看是否有人可以帮助确定我遇到的问题。
这是我收到的比特流消息的图片:
这是相应的日志输出:
这些列应该是消息长度 + 4、总消息长度、消息 ID 和来自发件人的 IP:
正如我所见,第一条消息的长度前缀(一次发送给我的多条消息)完全太大了。我从 95.211.212.26 收到的第五条消息是一个格式正确的位域消息。
我注意到的另一件事是,每条多消息消息的假定消息 ID 为 255。此外,鉴于此给定 torrent 的位域消息的总长度为 126,总长度 (303, 328 , 325) 对于一个位域的消息后跟几个 have 消息来说并不是不可想象的。
好吧,我已经设法弄清楚我哪里出错了。我正在从套接字中读取,假设我的消息会完整存在。实际上,我正在阅读消息的初始片段,稍后我正在阅读消息的中间部分。我看到的 255 个值不是消息 ID,实际上是对等位域 (0xff) 的中间值。
我改变了我的方法,以字节为单位将从套接字读取的数据存储到对等方的消息缓冲区。一旦消息缓冲区至少与预期的有效负载一样长,我就会读取消息并修剪缓冲区以排除我刚刚读取的内容。现在我所有消息的 ID 都符合我的预期。
我正在 python 中编写一个 bittorrent 客户端,并且一直在使用循环从使用 recv() 的对等套接字不断读取消息。
当我 运行 我的程序时,我在 wireshark 中查看我收到的比特流消息。很容易从消息的前 5 个字节中判断出您得到的是哪种消息,因为长度和消息 ID 已在此处指定。
我 运行 在处理接收包含多条消息的数据时遇到了一些问题。
我尝试通过编写这样的方法来解决它:
def handleMultiple(self, message, peer):
total_length = len(message)
parsed = 0
while parsed < total_length:
m_len, m_id = struct.unpack(">IB", message[parsed:parsed + 5])
m_total = m_len + 4
print(m_len, total_length, parsed, m_id, peer.made_handshake, peer.ip)
self.handleMessage(message[parsed:m_total + parsed], peer)
parsed += m_total
该函数只是将接收到的字节分解为其组成消息,并将其交给知道如何处理各个消息的消息处理程序。
问题是,当我从使用 recv() 收到的消息中打印出长度前缀和消息 ID 时,有时它看起来只是垃圾数字。
这真的是我第一次尝试使用套接字,所以我缺乏直觉,无法知道调用 recv() 时我真正得到了什么。我是否应该只对收到的前 5 个字节的数据调用 receive,然后进行一些检查以确保长度和 ID 有效,然后对消息的其余部分调用 recv()?
我应该如何处理一次传入的多条消息?
编辑:
我想提供一些我看到的结果图片,看看是否有人可以帮助确定我遇到的问题。
这是我收到的比特流消息的图片:
这是相应的日志输出: 这些列应该是消息长度 + 4、总消息长度、消息 ID 和来自发件人的 IP:
正如我所见,第一条消息的长度前缀(一次发送给我的多条消息)完全太大了。我从 95.211.212.26 收到的第五条消息是一个格式正确的位域消息。
我注意到的另一件事是,每条多消息消息的假定消息 ID 为 255。此外,鉴于此给定 torrent 的位域消息的总长度为 126,总长度 (303, 328 , 325) 对于一个位域的消息后跟几个 have 消息来说并不是不可想象的。
好吧,我已经设法弄清楚我哪里出错了。我正在从套接字中读取,假设我的消息会完整存在。实际上,我正在阅读消息的初始片段,稍后我正在阅读消息的中间部分。我看到的 255 个值不是消息 ID,实际上是对等位域 (0xff) 的中间值。
我改变了我的方法,以字节为单位将从套接字读取的数据存储到对等方的消息缓冲区。一旦消息缓冲区至少与预期的有效负载一样长,我就会读取消息并修剪缓冲区以排除我刚刚读取的内容。现在我所有消息的 ID 都符合我的预期。