You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Root-me TCP返校挑战C++实现求助:结果发送失败排查

解决root-me.org「TCP-Back to school」挑战的发送问题

问题背景

  • 挑战任务:通过IPv6 TCP连接到2001:bc8:35b0:c166::151:52002,解析服务器发送的数学题计算num1的平方根并乘以num2,将结果四舍五入到两位小数,在2秒内以二进制int/float类型发送给服务器(注意:不是字符串形式)
  • 遇到的问题:
    • 发送字符串格式的结果时,服务器返回[!] Please only send int/float !
    • 直接发送float精度不足,发送double无响应,多数情况下服务器无反馈

当前代码的核心问题

你的代码错误地将计算结果转换为ASCII字符串发送,而服务器要求的是二进制格式的数值数据(即直接发送float或int类型的内存字节)。此外:

  • 使用ceil实现向上取整,不符合挑战要求的四舍五入
  • 发送字符串时存在拼接错误(如测试输出中出现8807.008807这类异常内容)

修复方案

关键改动点

  1. 用round()函数实现正确的四舍五入到两位小数
  2. 将计算结果转换为32位float类型,直接发送其二进制内存数据
  3. 确保发送的字节长度为sizeof(float),而非字符串长度

修改后的完整代码

// TCP - Retour au collège
#include <sys/socket.h> 
#include <iostream>
#include <cmath>
#include <cstring>
#include <netinet/in.h>
#include <unistd.h>
#include <iomanip>
#include <arpa/inet.h>
#include <string>

int main() {
    // Connect to root-me.org with tcp (this script is client side)
    int client = socket(AF_INET6, SOCK_STREAM, 0);
    if (client == -1) {
        std::cerr << "Socket creation failed" << std::endl;
        return 1;
    }
    
    // set socket address type to network type 
    struct sockaddr_in6 serv;
    std::memset(&serv, 0, sizeof(serv));
    serv.sin6_family = AF_INET6;
    serv.sin6_port = htons(52002);
    if (inet_pton(AF_INET6, "2001:bc8:35b0:c166::151", &serv.sin6_addr) != 1) {
        std::cerr << "Invalid IPv6 address" << std::endl;
        close(client);
        return 1;
    }
    
    // Connect to server
    if (connect(client, (struct sockaddr*)&serv, sizeof(serv)) == -1) {
        std::cerr << "Connection failed" << std::endl;
        close(client);
        return 1;
    }
    std::cout << "Connected to port 52002" << std::endl;
    
    //Receive data and processing
    char buffer[1024] = { 0 }; 
    ssize_t recv_len = recv(client, buffer, sizeof(buffer)-1, 0); 
    if (recv_len <= 0) {
        std::cerr << "Receive failed or server closed connection" << std::endl;
        close(client);
        return 1;
    }
    buffer[recv_len] = '\0'; // Ensure null termination
    std::cout << "Message from serv:\n" << buffer << std::endl;
    
    std::string str = buffer;
    size_t sqrt_pos = str.find("square root of ");
    size_t multiply_pos = str.find(" and multiply by ");
    size_t equal_pos = str.find(" = ");
    
    // Parse numbers with error checking
    if (sqrt_pos == std::string::npos || multiply_pos == std::string::npos || equal_pos == std::string::npos) {
        std::cerr << "Failed to parse server message" << std::endl;
        close(client);
        return 1;
    }
    
    std::string number1 = str.substr(sqrt_pos + strlen("square root of "), multiply_pos - (sqrt_pos + strlen("square root of ")));
    int number1_ = std::stoi(number1);
    std::string number2 = str.substr(multiply_pos + strlen(" and multiply by "), equal_pos - (multiply_pos + strlen(" and multiply by ")));
    int number2_ = std::stoi(number2);
    
    double res = std::sqrt(number1_) * number2_;
    std::cout << "Raw result: " << std::setprecision(15) << res << std::endl;
    
    // Correct rounding to two decimal places
    res = std::round(res * 100.0) / 100.0;
    std::cout << "Rounded result: " << std::fixed << std::setprecision(2) << res << std::endl;
    
    // Convert to float and send as binary
    float res_float = static_cast<float>(res);
    ssize_t send_len = send(client, &res_float, sizeof(res_float), 0);
    if (send_len != sizeof(res_float)) {
        std::cerr << "Failed to send full data" << std::endl;
        close(client);
        return 1;
    }
    std::cout << "Sent binary float (size: " << sizeof(res_float) << " bytes)" << std::endl;
    
    // Receive server response
    char buffer1[1024] = { 0 }; 
    ssize_t recv_len1 = recv(client, buffer1, sizeof(buffer1)-1, 0); 
    if (recv_len1 > 0) {
        buffer1[recv_len1] = '\0';
        std::cout << "\nServer response:\n" << buffer1 << std::endl;
    } else {
        std::cerr << "No response from server or connection closed" << std::endl;
    }
   
    //closing&ending
    close(client); 
    return 0;
}

改动说明

  • 增加了错误检查:socket创建、连接、接收、解析步骤的错误处理,避免程序崩溃
  • 替换ceil为round:实现标准四舍五入(ceil是向上取整,会导致结果偏大)
  • 发送逻辑修改:直接发送float类型的内存数据,长度为sizeof(float)(通常4字节),而非字符串
  • 确保字符串解析的正确性:调整了子串截取的计算方式,避免越界

测试验证

运行修改后的代码后,服务器应该会返回正确的响应(包含挑战的flag)。如果仍然无响应,检查:

  • 是否在2秒内完成计算和发送(当前代码的计算逻辑足够快,不会超时)
  • 网络环境是否允许访问IPv6地址
  • 是否正确处理了服务器的完整消息(增加的错误检查会提示解析失败的情况)

内容的提问来源于stack exchange,提问作者Get

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 12:05:09