从 torrent 节点接收片段

问题描述 投票:0回答:1

我正在尝试用 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;
}
c networking tcp torrent
1个回答
0
投票

根据您的代码,问题似乎可能在于您如何形成和发送片段请求消息以及处理接收到的数据。以下是一些潜在的问题以及调试和解决问题的建议:

  1. 件请求消息的正确长度

    • 在 BitTorrent 协议中,一条请求消息由固定长度 13 个字节组成:1 个字节为消息 ID,12 个字节为负载(索引、开始和长度均为 4 个字节)。
    • 发送消息时请确保长度设置正确。
  2. 正确处理接收到的数据

    • receiveData
      函数应确保它准确读取请求的长度。
    • 如果
      recv
      返回0,则表示连接已关闭。你应该妥善处理这种情况。
  3. 使用日志进行调试:

    • 添加详细的日志记录以确保每个步骤正常工作。
    • 记录发送和接收的确切字节,以了解请求和响应是否正确。

这是包含上述建议的代码的修订版本:

更新代码

发送数据

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);

调试技巧

  1. 确保网络字节顺序:

    • 始终使用
      htonl
      htons
      将多字节整数转换为网络字节顺序。
  2. 检查消息形成

    • 使用像 Wireshark 这样的数据包嗅探器来检查发送和接收的实际字节。这将帮助您验证消息的正确性。
  3. 处理部分读/写

    • 确保您的
      sendData
      receiveData
      函数正确处理部分读取和写入。
  4. 添加更多日志:

    • 在发送前和接收后记录消息内容以验证其正确性。

通过实施这些建议并改进日志记录,您应该能够确定问题所在并进行必要的更正。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.