Ich habe ein Problem mit dem Senden mehrerer Back-to-Back separate UDP-Puffer mit Boost Asio. Ich habe einen 1-Sekunden-Asio-Timer, der einen Callback auslöst, der eine 2 separate UDP-Datagrammstrukturen über UDP überträgt. Jede dieser Nachrichtenstrukturen wird über std :: unique_ptr zugewiesen, so dass sie nicht zu dem Zeitpunkt, zu dem der asynchrone Aufruf von CADaemon :: handle_send aufgerufen wird, den Gültigkeitsbereich verlassen sollten.mehrere Rücken an Rücken boost :: asio async_send_to Anrufe Ursache Pufferüberlauf
void
CADaemon::heartBeatTimer(
const milliseconds& rHeartBeatMs)
{
mpStatusTimer->expires_from_now(rHeartBeatMs);
mpStatusTimer->async_wait(boost::bind(
&CADaemon::heartBeatTimer,
this, rHeartBeatMs));
if (mpALBFSocket && mpALBFEndpoint) {
mpALBFSocket->async_send_to(
buffer(mpStatusMessage.get(),
sizeof(MemberSystemStatusMessage)),
*mpALBFEndpoint,
boost::bind(&CADaemon::handle_send, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
// must insert delay to prevent buffer overwrites
std::this_thread::sleep_for(std::chrono::milliseconds(10);
// heartbeat messages are also sent to this socket/endpoint
mpALBFSocket->async_send_to(
buffer(mpHeartbeatMessage.get(),
sizeof(CAServiceHeartbeatMessage)),
*mpALBFEndpoint,
boost::bind(&CADaemon::handle_send, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
}
Die empfangende Anwendung funktioniert, wenn ich eine kleine Verzögerung setzen zwischen der ersten Nachricht und die zweite Nachricht, aber senden, wenn ich sie schicken, wie sie sind, erscheint es, dass der zweite Puffer die erste von der Zeit überschreibt es kommt in der empfangenden Anwendung an.
Was mache ich falsch?
Ich habe auch versucht, mehrere Puffer mit dem Code unten zu senden, aber das verhält sich schlechter, da es beide Datagramme als ein einzelnes langes Datagramm zusammenführt.
void
CADaemon::heartBeatTimer(
const milliseconds& rHeartBeatMs)
{
mpStatusTimer->expires_from_now(rHeartBeatMs);
mpStatusTimer->async_wait(boost::bind(
&CADaemon::heartBeatTimer,
this, rHeartBeatMs));
if (mpALBFSocket && mpALBFEndpoint) {
std::vector<boost::asio::const_buffer> transmitBuffers;
transmitBuffers.push_back(buffer(
mpStatusMessage.get(),
sizeof(MemberSystemStatusMessage)));
//transmitBuffers.push_back(buffer(
// mpHeartbeatMessage.get(),
// sizeof(CAServiceHeartbeatMessage)));
mpALBFSocket->async_send_to(
transmitBuffers, *mpALBFEndpoint,
boost::bind(&CADaemon::handle_send, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
}
Hier sind die Mitglieder der Klasse, die an der ASIO aus der zugehörigen Headerdatei beteiligt sind
// this message is transmitted @1HZ
std::unique_ptr<MemberSystemStatusMessage> mpStatusMessage;
// this message is transmitted @1HZ
std::unique_ptr<CAServiceHeartbeatMessage> mpHeartbeatMessage;
// this message is received @1HZ
std::unique_ptr<WOperationalSupportMessage> mpOpSupportMessage;
// this message is received @1HZ when valid
std::unique_ptr<MaintenanceOTPMessage> mpOTPMessage;
std::shared_ptr<boost::asio::io_service> mpIOService;
std::unique_ptr<boost::asio::ip::udp::socket> mpALBFSocket;
std::unique_ptr<boost::asio::ip::udp::endpoint> mpALBFEndpoint;
std::unique_ptr<boost::asio::ip::udp::socket> mpServerSocket;
std::unique_ptr<boost::asio::ip::udp::endpoint> mpServerEndpoint;
std::unique_ptr<boost::asio::steady_timer> mpStatusTimer;
std::unique_ptr<uint8_t[]> mpReceiveBuffer;
Diese Der Handler
Rückruf istvoid
CADaemon::handle_send(
const boost::system::error_code& error,
std::size_t bytes_transferred)
{
static auto& gEvtLog = gpLogger->getLoggerRef(
Logger::LogDest::EventLog);
if (!error || (error == boost::asio::error::message_size)) {
// Critical Section - exclusive write
boost::unique_lock<boost::shared_mutex> uniqueLock(gRWMutexGuard);
LOG_EVT_INFO(gEvtLog) << *mpStatusMessage;
LOG_EVT_INFO(gEvtLog) << *mpHeartbeatMessage;
LOG_EVT_INFO(gEvtLog) << "Sent " << bytes_transferred << " bytes";
mpStatusMessage->incrementSequenceCounter();
} else {
LOG_EVT_ERROR(gEvtLog) << "handle_send: asio error code["
<< error.value() << "]";
}
}
EDIT: added bemerkt DIE DEN EMPFANG Java-Anwendung Code mit dem BUFFER KORRUPTION
Der folgende Code den Code in der empfangenden Java-Anwendung zeigt, dass die Größe des empfangenen Datagramms niemals beschädigt ist, nur der Inhalt, die Größe scheint immer die des längeren Datagramms zu sein. Hoffe, das ist nützlich, um das Problem aufzuspüren.
@Override
protected Task<Void> createTask() {
return new Task<Void>() {
@Override
protected Void call() throws Exception {
updateMessage("Running...");
try {
DatagramSocket serverSocket = new DatagramSocket(mPortNum);
// allocate space for received datagrams
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
while (!isCancelled()) {
serverSocket.receive(packet);
int bytesReceived = packet.getLength();
MemberSystemStatusMessage statusMessage =
new MemberSystemStatusMessage();
int statusMessageSize = statusMessage.size();
CAServiceHeartbeatMessage heartbeatMessage =
new CAServiceHeartbeatMessage();
int heartbeatMessageSize = heartbeatMessage.size();
if (Platform.isFxApplicationThread()) {
if (bytesReceived == statusMessage.size()) {
statusMessage.setByteBuffer(ByteBuffer.wrap(bytes), 0);
setMemberSystemMessage(statusMessage);
} else if (bytesReceived == heartbeatMessage.size()){
heartbeatMessage.setByteBuffer(ByteBuffer.wrap(bytes), 0);
setHeartbeatMessage(heartbeatMessage);
} else {
System.out.println("unexpected datagram");
}
} else { // update later in FxApplicationThread
if (bytesReceived == statusMessage.size()) {
statusMessage.setByteBuffer(ByteBuffer.wrap(bytes), 0);
Platform.runLater(() -> setMemberSystemMessage(statusMessage));
} else if (bytesReceived == heartbeatMessage.size()){
heartbeatMessage.setByteBuffer(ByteBuffer.wrap(bytes), 0);
Platform.runLater(() -> setHeartbeatMessage(heartbeatMessage));
} else {
System.out.println("unexpected datagram");
}
}
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
updateMessage("Cancelled");
return null;
}
};
}
}
Wenn Boost.Asio wird der TR2-Vorschlag entsprechen, dann scheint die Reihenfolge angegeben werden. Ich stimme zu, dass das Protokoll Pakete fallen lassen darf. In diesem Fall ist jedoch auch ein Fehler in der empfangenden Anwendung möglich/wahrscheinlich. – janm
@TannerSansbury danke für das Fortbestehen und das Finden, dass das Problem tatsächlich der Kunde war, gut gemacht! – johnco3
@TannerSansbury Ich frage mich, ob Sie eine Follow-up-Frage http://stackoverflow.com/questions/36626870/java-nio-datagramchannel-corruption - Ich änderte meine Java-Code NIO verwenden und ich habe nie wirklich verstanden, warum ich hatte um die Bytes schnell zu kopieren, bevor die nächste Nachricht die vorhandenen Empfangspufferbytes beschädigte. Ich dachte, dass bei einem ausreichend großen Empfangspuffer der nächste Schreibvorgang in den Empfangspuffer den vorherigen Puffer nicht beschädigen würde – johnco3