So I have a sender program(written in python) that send a API response to this c++ application using UDP socket.
Below is python code that send data :
# 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}
Below is the receiver code 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;
}
and the output I am getting is below:
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
I am not sure how I am getting this issue, in struct Instructions if I use std::string instead of std::array<uint8_t,100> then it works fine.
Any help would be appreciated.
The cause is here:
If the type is
std::array, then you always print 100 bytes, even if some of them are null or garbage.If the type is
std::stringand if constructed correctly, it will be null-terminated and the iteration will stop on null.You either want to stop iterating over
std::arrayas soon as you hit null, or just usestd::cout<<array.data()if the string is always null-terminated.