从UDP套接字获取数据时出现垃圾数据
我有一个发送程序(用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()
。