从UDP套接字获取数据时出现垃圾数据

0 投票
1 回答
52 浏览
提问于 2025-04-14 18:12

我有一个发送程序(用Python写的),它通过UDP套接字把API的响应发送给一个C++应用程序。

下面是发送数据的Python代码:

# Function to send data via UDP socket
def send_data_via_udp(data):
    # UDP server address and port
    udp_server_address = ('127.0.0.1', 12343)  # Change this to your destination UDP server address and port

    # Create a UDP socket
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    try:
        # Convert data to JSON string
        json_data = json.dumps(data)
        
        # Send data via UDP socket
        udp_socket.sendto(json_data.encode(), udp_server_address)
        
        print("Data sent via UDP successfully.")
    except Exception as e:
        print("Error while sending data via UDP:", e)
    finally:
        # Close the UDP socket
        udp_socket.close()

data_to_send = {'path': coordinates, 'distance': distance, 'instruction': instruction, 'time': time}

下面是接收数据的C++代码:

struct Instruction
{
    int type;
    std::array<uint8_t, 100> instruction;
    std::array<uint8_t, 100> verbal_transition_alert_instruction;
    std::array<uint8_t, 50> verbal_succinct_transition_instruction;
    std::array<uint8_t, 100> verbal_pre_transition_instruction;
    std::array<uint8_t, 100> verbal_post_transition_instruction;
    std::vector<std::string> street_names;
    std::vector<std::string> begin_street_names;
    double time;
    double length;
    double cost;
    int begin_shape_index;
    int end_shape_index;
    std::array<uint8_t, 50> travel_mode;
    std::array<uint8_t, 50> travel_type;
};

// Structure to store the received data
struct ReceivedData
{
    std::vector<std::pair<double, double>> path;
    double distance;
    std::vector<Instruction> instructions;
    double time;
};

// Function to parse JSON data and extract the required fields
ReceivedData parseJsonData(const std::string &jsonData)
{
    ReceivedData data;
    Json::Value root;
    Json::Reader reader;

    // Parse JSON
    if (!reader.parse(jsonData, root))
    {
        std::cerr << "Error parsing JSON data: " << reader.getFormattedErrorMessages() << std::endl;
        return data; // Return empty data in case of parsing error
    }

    try
    {
        // Extract path coordinates
        const Json::Value &pathArray = root["path"];
        for (const auto &coord : pathArray)
        {
            double lat = coord[0].asDouble();
            double lon = coord[1].asDouble();
            data.path.push_back(std::make_pair(lat, lon));
        }

        // Extract distance
        data.distance = root["distance"].asDouble();

        // Extract instructions
        const Json::Value &instructionArray = root["instruction"];
        for (const auto &instr : instructionArray)
        {
            Instruction instruction;
            instruction.type = instr["type"].asInt();
            // Convert JSON strings to std::array<uint8_t, 100>
            std::string instructionStr = instr["instruction"].asString();
            std::copy(instructionStr.begin(), instructionStr.end(), instruction.instruction.begin());

            std::string verbalTransitionAlertStr = instr["verbal_transition_alert_instruction"].asString();
            std::copy(verbalTransitionAlertStr.begin(), verbalTransitionAlertStr.end(), instruction.verbal_transition_alert_instruction.begin());

            std::string verbalSuccinctTransitionStr = instr["verbal_succinct_transition_instruction"].asString();
            std::copy(verbalSuccinctTransitionStr.begin(), verbalSuccinctTransitionStr.end(), instruction.verbal_succinct_transition_instruction.begin());

            std::string verbalPreTransitionStr = instr["verbal_pre_transition_instruction"].asString();
            std::copy(verbalPreTransitionStr.begin(), verbalPreTransitionStr.end(), instruction.verbal_pre_transition_instruction.begin());

            instruction.verbal_post_transition_instruction = stringToArray(instr["verbal_post_transition_instruction"].asString());

            std::copy(verbalPostTransitionStr.begin(), verbalPostTransitionStr.end(), instruction.verbal_post_transition_instruction.begin());
            instruction.verbal_post_transition_instruction[verbalPostTransitionStr.size()] = '\0';

            // for(size_t i = 0; i<verbalPostTransitionStr.size() && i<100; ++i){
            //     instruction.verbal_post_transition_instruction[i] = static_cast<uint8_t>(verbalPostTransitionStr[i]);
            // }
           // std::copy(verbalPostTransitionStr.begin(), verbalPostTransitionStr.end(), instruction.verbal_post_transition_instruction.begin());
            //instruction.verbal_post_transition_instruction[verbalPostTransitionStr.size()] = '\0';
            // Ensure null-termination

            // if (verbalPostTransitionStr.size() < 100)
            // {
            //     instruction.verbal_post_transition_instruction[verbalPostTransitionStr.size()] = '\0';
            // }

            for (const auto &street : instr["street_names"])
            {
                instruction.street_names.push_back(street.asString());
            }
            for (const auto &begin_street : instr["begin_street_names"])
            {
                instruction.begin_street_names.push_back(begin_street.asString());
            }
            instruction.time = instr["time"].asDouble();
            instruction.length = instr["length"].asDouble();
            instruction.cost = instr["cost"].asDouble();
            instruction.begin_shape_index = instr["begin_shape_index"].asInt();
            instruction.end_shape_index = instr["end_shape_index"].asInt();
            std::string travelModeStr = instr["travel_mode"].asString();
            std::copy(travelModeStr.begin(), travelModeStr.end(), instruction.travel_mode.begin());
            std::string travelTypeStr = instr["travel_type"].asString();
            std::copy(travelTypeStr.begin(), travelTypeStr.end(), instruction.travel_type.begin());


            data.instructions.push_back(instruction);
        }

        // Extract time
        data.time = root["time"].asDouble();
    }
    catch (const std::exception &e)
    {
        std::cerr << "Error extracting data from JSON: " << e.what() << std::endl;
    }

    return data;
}

int main()
{
    // Create a UDP socket
    int udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
    if (udpSocket < 0)
    {
        std::cerr << "Error in socket creation" << std::endl;
        return -1;
    }

    // Bind the socket to an address and port
    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = INADDR_ANY; // Bind to any address
    serverAddr.sin_port = htons(RECEIVER_PORT);

    if (bind(udpSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
    {
        std::cerr << "Bind failed" << std::endl;
        return -1;
    }

    struct sockaddr_in senderAddr;
    socklen_t senderSize = sizeof(senderAddr);
    char buffer[45008]; // Increase buffer size to accommodate larger JSON data

    while (true)
    {
        std::cout << "Waiting for data..." << std::endl;

        // Wait for data to receive
        ssize_t bytesReceived = recvfrom(udpSocket, buffer, sizeof(buffer), 0, (struct sockaddr *)&senderAddr, &senderSize);
        if (bytesReceived < 0)
        {
            std::cerr << "Error in recvfrom()" << std::endl;
            break;
        }

        std::string receivedData(buffer, bytesReceived);
        std::cout << "Received data: " << receivedData << std::endl;

        // Parse received JSON data
        ReceivedData parsedData = parseJsonData(receivedData);

        // Print extracted data
        std::cout << "Path coordinates:" << std::endl;
        for (const auto &coord : parsedData.path)
        {
            std::cout << "(" << coord.first << ", " << coord.second << ")" << std::endl;
        }

        std::cout << "Distance: " << parsedData.distance << std::endl;

        std::cout << "Instructions:" << std::endl;
        for (const auto &instr : parsedData.instructions)
        {
            std::cout << "Type: " << instr.type << std::endl;
            std::cout << "Instruction: ";
            for (const auto &value : instr.instruction)
            {
                std::cout << static_cast<char>(value);
            }
            std::cout << std::endl;

            std::cout << "Verbal Post Transition Instruction: ";

            for (const auto &value : instr.verbal_post_transition_instruction)
            {
                std::cout << static_cast<char>(value);
            }
            std::cout << std::endl;
            // Print other instruction fields as needed
        }

        std::cout << "Time: " << parsedData.time << std::endl;
    }

    // Close the socket
    close(udpSocket);

    return 0;
}

我得到的输出如下:

Instruction: Bear left to stay on Mehrauli Gurgaon Road/NH148A.
Verbal Post Transition Instruction: Continue for 400 meters.��"�zU,��,����3
Type: 16
Instruction: Bear left to stay on Mehrauli Gurgaon Road/NH148A.
Verbal Post Transition Instruction: Continue for 30 meters.��"�zU,��,����3
Type: 24
Instruction: Keep left to stay on Mehrauli Gurgaon Road/NH148A.
Verbal Post Transition Instruction: Continue for 200 meters.��"�zU,��,����3
Type: 23
Instruction: Keep right to stay on Mehrauli Gurgaon Road/NH148A.
Verbal Post Transition Instruction: Continue for 100 meters.��"�zU,��,����3
Type: 23
Instruction: Keep right to stay on Mehrauli Gurgaon Road/NH148A.
Verbal Post Transition Instruction: Continue for 2.5 kilometers.��"�zU,��,����3
Type: 23
Instruction: Keep right to stay on Mehrauli Gurgaon Road/NH148A.
Verbal Post Transition Instruction: Continue for 200 meters.rs.��"�zU,��,����3
Type: 23
Instruction: Keep right to take Mehrauli-Gurgaon Road.ad/NH148A.
Verbal Post Transition Instruction: Continue for 80 meters.rs.��"�zU,��,����3
Type: 23
Instruction: Keep right to stay on Mehrauli-Gurgaon Road.NH148A.
Verbal Post Transition Instruction: Continue for 1 kilometer.s.��"�zU,��,����3
Type: 23
Instruction: Keep right to stay on Mehrauli-Gurgaon Road.NH148A.
Verbal Post Transition Instruction: Continue for 3 kilometers..��"�zU,��,����3

我不太明白为什么会出现这个问题。在struct Instructions中,如果我用std::string替代std::array<uint8_t,100>,那就没问题了。

任何帮助都非常感谢。

1 个回答

0

问题的原因在这里:

            for (const auto &value : instr.verbal_post_transition_instruction)
            {
                std::cout << static_cast<char>(value);
            }

如果类型是 std::array,那么你打印出来的总是100个字节,即使其中有些是空值或者垃圾数据。

如果类型是 std::string,并且构造得当,它会以空字符结束,这样在遍历时就会在遇到空字符时停止。

你要么希望在遍历 std::array 时,一遇到空值就停止,要么如果字符串总是以空字符结束,就直接使用 std::cout<<array.data()

撰写回答