我正在尝试用 C 语言编写一个 torrent 客户端,到目前为止我已经编写了 Bencode Parser,但我陷入了网络部分。
根据规格规格在初次握手并发送感兴趣的消息后,我们可以请求一块。
我能够发送和接收握手消息,发送感兴趣的消息,但无法获取任何片段。
这是我用来遵循该过程的代码
bt_msg_t 结构取自 Swathmore 实验室作业指南(PgNo.5)
//Piece-Request
bt_msg_t Sendmsg;
Sendmsg.bt_type = BT_REQUEST;
Sendmsg.payload.request.begin = 0;
Sendmsg.payload.request.index = 0;
Sendmsg.payload.request.length = 4;
Sendmsg.length = sizeof(Sendmsg.bt_type)+sizeof(Sendmsg.payload);
assert(sendData(sockfd, (char*)&Sendmsg, sizeof(Sendmsg)) == 1);
//SendData is a wrapper over send() tcp function
//Fetching the Piece
do {
receiveData(sockfd, 8, buffer, 1);//recvData() is a wrapper over receiveData
memcpy(&Recvmsg, buffer, sizeof(Sendmsg));
memset(buffer, 0, sizeof(buffer));
} while (Recvmsg.bt_type!=BT_PIECE);
//
代码卡在获取片段部分,并且对等方没有响应所请求的片段,是对等方故障还是我的代码有问题?
这是我自己创建的 torrent 文件,我用作参考TorrentFile
我正在使用的 sendData() 和 receiveData() 代码片段。
int sendData(int sockfd,char data[],ssize_t len)
{
ssize_t tot_sent = 0;
// ssize_t len = 68;
while (tot_sent < len) {
ssize_t sent = send(sockfd, data, len - tot_sent, 0);
if (sent < 0)
{
std::cout << "No data sent\n";
return -1;
}
std::cout << "Sent:" << sent << '\n';
tot_sent += sent;
handshake += sent;
}
return 1;
}
int receiveData(int sockfd, ssize_t len, char* buff, int flag)
{
unsigned tot_recv = 0;
ssize_t nb=0;
// char buff[len];
if (len == 0) {
std::cout << "No data available" << '\n';
return -1;
}
do {
assert(len - tot_recv > 0);
nb = recv(sockfd, buff + tot_recv, len - tot_recv, 0);
if (nb < 0) {
std::cout << "No data received" << '\n';
return -1;
}
std::cout << "Received in chunks :" << nb << "\n";
tot_recv += nb;
} while (nb > 0 && tot_recv < len);
if (tot_recv == len) {
std::cout << "Received All" << '\n';
return 1;
// return;
}
return -1;
}
根据您的代码,问题似乎可能在于您如何形成和发送片段请求消息以及处理接收到的数据。以下是一些潜在的问题以及调试和解决问题的建议:
件请求消息的正确长度:
正确处理接收到的数据:
receiveData
函数应确保它准确读取请求的长度。recv
返回0,则表示连接已关闭。你应该妥善处理这种情况。使用日志进行调试:
这是包含上述建议的代码的修订版本:
int sendData(int sockfd, char data[], ssize_t len)
{
ssize_t tot_sent = 0;
while (tot_sent < len) {
ssize_t sent = send(sockfd, data + tot_sent, len - tot_sent, 0);
if (sent < 0) {
std::cout << "No data sent\n";
return -1;
}
std::cout << "Sent:" << sent << '\n';
tot_sent += sent;
}
return 1;
}
int receiveData(int sockfd, ssize_t len, char* buff, int flag)
{
ssize_t tot_recv = 0;
ssize_t nb = 0;
while (tot_recv < len) {
nb = recv(sockfd, buff + tot_recv, len - tot_recv, flag);
if (nb <= 0) {
std::cout << "No data received\n";
return -1;
}
std::cout << "Received in chunks :" << nb << "\n";
tot_recv += nb;
}
std::cout << "Received All\n";
return 1;
}
bt_msg_t Sendmsg;
Sendmsg.bt_type = BT_REQUEST;
Sendmsg.payload.request.begin = htonl(0); // Convert to network byte order
Sendmsg.payload.request.index = htonl(0); // Convert to network byte order
Sendmsg.payload.request.length = htonl(4); // Convert to network byte order
// The length should be 13 (1 byte for type + 12 bytes for payload)
Sendmsg.length = sizeof(Sendmsg.bt_type) + sizeof(Sendmsg.payload.request);
assert(sendData(sockfd, (char*)&Sendmsg, Sendmsg.length) == 1);
bt_msg_t Recvmsg;
char buffer[1024]; // Ensure this buffer is large enough for expected data
do {
if (receiveData(sockfd, 8, buffer, 0) != 1) {
std::cout << "Failed to receive data\n";
break;
}
memcpy(&Recvmsg, buffer, 8); // Copy only the first 8 bytes for message length and type
// You may need additional code to handle the rest of the piece message based on the length
int piece_length = ntohl(*((int*)buffer)) + 4; // Get the full length of the piece message
if (receiveData(sockfd, piece_length - 8, buffer + 8, 0) != 1) {
std::cout << "Failed to receive full piece data\n";
break;
}
memcpy((char*)&Recvmsg + 8, buffer + 8, piece_length - 8);
} while (Recvmsg.bt_type != BT_PIECE);
确保网络字节顺序:
htonl
或 htons
将多字节整数转换为网络字节顺序。检查消息形成:
处理部分读/写:
sendData
和 receiveData
函数正确处理部分读取和写入。添加更多日志:
通过实施这些建议并改进日志记录,您应该能够确定问题所在并进行必要的更正。