BitTorrent客户端实现:Peer忽略分片请求问题排查
问题定位
你的实现没有遗漏核心交互流程,块大小、分片索引、偏移参数也都符合规范,问题出在两个认知偏差和一个发送逻辑错误上:
对Transmission peer状态标识的方向理解错误
你看到的?I状态完全是正常的:- 第一个字符
?确实代表Transmission未choke你的客户端,和你收到unchoke消息的实际状态一致。 - 第二个字符
I代表Transmission对你的客户端不感兴趣,不是指你没有成功发送interested消息——你发送的是全零bitfield,没有任何Transmission需要的分片,它作为做种端不需要从你这里下载任何数据,显示not interested是符合逻辑的。
- 第一个字符
核心错误:request消息发送时的组包逻辑不符合
gen_tcp {packet,4}的工作机制{packet,4}模式的行为是:对你每次调用gen_tcp.send/2传入的完整二进制块,统一在头部添加一个4字节的大端长度前缀,它不会自动拆分你传入内容里包含的多个独立Peer消息。
如果你把两个13字节的request载荷拼接成一个26字节的二进制一次性发送,gen_tcp会为这26字节添加值为26的长度前缀,Transmission收到后会把整段26字节当成一条request消息解析。但标准request消息的固定长度是13字节(1字节消息ID+4字节index+4字节begin+4字节length),长度为26的request消息属于非法格式,会被Transmission直接丢弃,不会生成任何待处理请求,这就是你看不到待处理请求、也收不到piece响应的根本原因。
正确的发送方式是:每条request单独调用一次send,每次只传入13字节的单条request载荷,gen_tcp会自动为每条消息添加值为13的长度前缀,生成两条独立的合法请求。
补充说明
- 你提到的interested消息格式是正确的:只要你传给
gen_tcp.send的内容是<<2>>(没有手动额外加长度前缀),gen_tcp自动添加前缀后生成的就是符合规范的interested消息,Transmission能正常识别。 - 后续开发需要注意:如果连接过程中你收到Transmission发来的choke消息,之后再收到unchoke时,之前发过的所有未响应请求都会被对方作废,需要重新发送,不需要等超时再重发。
- 你当前使用的16384字节块大小、分片索引计算都没有问题,不需要调整。
内容的提问来源于stack exchange,提问作者lud
相关产品推荐
相关产品推荐

