Я пытаюсь настроить проект veins_inet (я реализовал пользовательскую карту SUMO и около 10 узлов. Эта симуляция работает без дополнений, которые я здесь представляю), и, в частности, отправляю сообщение, содержащее скорость, каждому транспортному средству в заданные периоды времени ( это совершенно не соответствует сообщениям, отправляемым во время аварии). Файл .msg, который у меня есть, задается просто:
import inet.common.INETDefs;
import inet.common.packet.chunk.Chunk;
//
// General message definition
//
class GeneralMessage extends inet::FieldsChunk
{
double Speed;
}
и файлы сериализатора, которые я написал для этих сообщений, даны:
// GeneralMessageSerializer.h
#ifndef __GENERALMESSAGESERIALIZER_H
#define __GENERALMESSAGESERIALIZER_H
#include "inet/common/packet/ChunkQueue.h"
#include "inet/common/packet/Packet.h"
#include "inet/common/packet/serializer/FieldsChunkSerializer.h"
#include "inet/common/packet/serializer/SequenceChunkSerializer.h"
#include "GeneralMessage_m.h"
namespace inet {
class GeneralMessageSerializer : public FieldsChunkSerializer
{
public:
virtual void serialize(MemoryOutputStream& stream, const Ptr<const Chunk>& chunk) const override;
virtual const Ptr<Chunk> deserialize(MemoryInputStream& stream) const override;
};
}
#endif // __GENERALMESSAGESERIALIZER_H
// GeneralMessageSerializer.cc
#include "GeneralMessageSerializer.h"
#include "GeneralMessage_m.h"
#include "inet/common/packet/chunk/ByteCountChunk.h"
#include "inet/common/packet/chunk/BytesChunk.h"
#include "inet/common/packet/ChunkBuffer.h"
#include "inet/common/packet/Packet.h"
#include "inet/common/packet/ReassemblyBuffer.h"
#include "inet/common/packet/ReorderBuffer.h"
#include "inet/common/packet/serializer/ChunkSerializerRegistry.h"
#include "inet/common/TimeTag_m.h"
namespace inet {
Register_Serializer(GeneralMessage, GeneralMessageSerializer);
#define ASSERT_ERROR(code, message) try { code; ASSERT(false); } catch (std::exception& e) { ASSERT((int)std::string(e.what()).find(message) != -1); };
void GeneralMessageSerializer::serialize(MemoryOutputStream& stream, const Ptr<const Chunk>& chunk) const
{
const auto& generalMessage = staticPtrCast<const GeneralMessage>(chunk);
// auto Speed = stream.getSpeed();
stream.writeUint32Be(generalMessage->getSpeed());
stream.writeByteRepeatedly(0, B(generalMessage->getChunkLength()).get());
}
const Ptr<Chunk> GeneralMessageSerializer::deserialize(MemoryInputStream& stream) const
{
auto generalMessage = makeShared<GeneralMessage>();
generalMessage->setSpeed(stream.readUint32Be());
stream.readByteRepeatedly(0, B(generalMessage->getChunkLength()).get());
return generalMessage;
}}
Это сообщение реализовано в образце приложения veins_inet путем добавления блока кода
int i;
for(i=25;i<150;i++){
// every node to send out a general message every second
auto callback = [this]() {
auto payload = makeShared<GeneralMessage>();
auto packet = createPacket("general");
payload->setChunkLength(B(150));
payload->setSpeed(traciVehicle->getSpeed());
timestampPayload(payload);
packet->insertAtBack(payload);
sendPacket(std::move(packet));
};
timerManager.create(veins::TimerSpecification(callback).oneshotAt(SimTime(i, SIMTIME_S)));
};
в функции StartApplication файла VeinsInetSampleApplication.cc. Как видите, я бы хотел, чтобы это GeneralMessage передавалось каждую секунду каждым узлом в моделировании, начиная с 25-й секунды. Для справки: у меня есть регистраторы Pcap на каждом узле для записи этих сообщений, но до сих пор мне не удалось сделать сообщение видимым в этих записях, поскольку я подозревал, что оно не сериализуется должным образом.
Ошибка, которую я получаю при попытке запустить это:
Неявная сериализация чанков отключена, чтобы предотвратить непредсказуемое снижение производительности (вы можете изменить флаг Chunk::enableImplicitChunkSerialization или передать флаг PF_ALLOW_SERIALIZATION для просмотра) -- в модуле (VeinsInetSampleApplication) Scenario.node[0].app[0] (id= 110), при t=25с, событие №143
В случае, если это также полезно, вот вывод из последней горстки событий перед появлением ошибки в консоли:
** Событие №133 t=25 Scenario.node[8].ipv4.ip (Ipv4, id=658) в общем (inet::Packet, id=1536)
ИНФОРМАЦИЯ: Получено (inet::Packet) общее из сети. ДЕТАЛИ: Получено дейтаграмма `' с dest=224.0.0.1 INFO:Доставка (inet::Packet)general (178 Б) [[inet::Ipv4Header, длина = 20 Б | inet::UdpHeader, порт: 9001-> 9001, длина полезной нагрузки: 150 Б, длина = 8 Б | Общее сообщение, длина = 150 В]] локально. ПРЕДУПРЕЖДЕНИЕ: Получена дейтаграмма «общая» без адрес источника заполнен INFO:Переход на протокол udp(57) ** Событие №134 t=25 Scenario.node[8].wlan[0].mac (Ieee80211Mac, id=622) в общем (inet::Packet, id=1528)
INFO:Кадр (inet::Packet)общий (208 Б) [[inet::ieee80211::Ieee80211DataHeader, длина = 24 Б | inet::Ieee80211EtherTypeHeader, длина = 2 B | инет:: Ipv4Header, длина = 20 В | inet::UdpHeader, порт:9001->9001, payloadLength:150 Б, длина = 8 В | GeneralMessage, длина = 150 Б | inet::ieee80211::Ieee80211MacTrailer, length = 4 B]] получено от верхний уровень, получатель = 01-00-5E-00-00-01 INFO (Dcf)Scenario.node[8].wlan[0].mac.dcf:Обработка верхнего фрейма: общее ИНФОРМАЦИЯ (PendingQueue)Scenario.node[8].wlan[0].mac.dcf.channelAccess.pendingQueue:Pushing пакет вообще в очередь. ДЕТАЛИ (Dcf)Scenario.node[8].wlan[0].mac.dcf:Запрос канала DETAIL (Конфликт)Scenario.node[8].wlan[0].mac.dcf.channelAccess.contention:Starting конкуренция: cw = 15, slots = 15, slotTime = 0,000013, ifs = 0,000058, eifs = 0,000178 ИНФОРМАЦИЯ (Конфликт)Scenario.node[8].wlan[0].mac.dcf.channelAccess.contention:Scheduling Конец состязания: отложенные слоты = 15, slotTime = 0,000013, lastBusyTime = 20.000152936058, lastIdle = -4611676.018427387903, waitInterval = 0. ** Событие №135 t=25 Scenario.node[0].udp (Udp, id=107) в общем (inet::Packet, id=1529)
INFO:Общий пакет получен из сети, порт назначения 9001 INFO:Отправка полезная нагрузка до сокета sockId=0 ** Событие #136 t=25 Scenario.node[1].udp (Udp, id=170) в общем (inet::Packet, id=1530)
INFO:Общий пакет получен из сети, порт назначения 9001 INFO:Отправка полезная нагрузка до сокета sockId=1 ** Событие №137 t=25 Scenario.node[2].udp (Udp, id=233) в общем (inet::Packet, id=1531)
INFO:Общий пакет получен из сети, порт назначения 9001 INFO:Отправка полезная нагрузка до сокета sockId=2 ** Событие #138 t=25 Scenario.node[3].udp (Udp, id=296) в общем (inet::Packet, id=1532)
INFO:Общий пакет получен из сети, порт назначения 9001 INFO:Отправка полезная нагрузка до сокета sockId=3 ** Событие #139 t=25 Scenario.node[4].udp (Udp, id=359) в общем (inet::Packet, id=1533)
INFO:Общий пакет получен из сети, порт назначения 9001 INFO:Отправка полезная нагрузка до сокета sockId=4 ** Событие №140 t=25 Scenario.node[5].udp (Udp, id=422) в общем (inet::Packet, id=1534)
INFO:Общий пакет получен из сети, порт назначения 9001 INFO:Отправка полезная нагрузка до сокета sockId=5 ** Событие №141 t=25 Scenario.node[7].udp (Udp, id=548) в общем (inet::Packet, id=1535)
INFO:Общий пакет получен из сети, порт назначения 9001 INFO:Отправка полезная нагрузка до сокета sockId=7 ** Событие №142 t=25 Scenario.node[8].udp (Udp, id=611) в общем (inet::Packet, id=1536)
INFO:Общий пакет получен из сети, порт назначения 9001 INFO:Отправка полезная нагрузка до сокета sockId=8 ** Событие №143 t=25 Scenario.node[0].app[0] (VeinsInetSampleApplication, id=110) в общем (inet::Packet, идентификатор = 1529)
Вы изменили тип сообщения, которое вы отправляете в VeinsInetSampleApplication
, но вы не изменили тип ожидаемого полученного сообщения.
Итак, в VeinsInetSampleApplication.cc
есть что-то вроде этого:
void VeinsInetSampleApplication::processPacket(std::shared_ptr<inet::Packet> pk)
{
auto payload = pk->peekAtFront<VeinsInetSampleMessage>(); // <-- causes an error
EV_INFO << "Received packet: " << payload << endl;
...
Поэтому при получении пакет обрабатывается как VeinsInetSampleMessage
, а не GeneralMessage
- это приводит к исключению.
Я предлагаю изменить эту строку на:
auto payload = pk->peekAtFront<GeneralMessage>();
И, конечно же, оставшаяся часть processPacket()
должна быть изменена соответствующим образом (например, GeneralMessage
не содержит roadId
, поэтому его нельзя читать).
VeinsInetApplicationBase
использует многоадресный IPv4-адрес (например, 224.0.0.1) в качестве адреса назначения, поэтому тип транспорта должен быть UDP. Поэтому вы не можете использовать TCP вместо UDP.
Еще раз спасибо. Можно ли каким-то образом изменить это, чтобы манипулировать типом протокола? Я вижу несколько типов протоколов в примере Pcap Showcase с Inet, но код кажется довольно минимальным, и из него сложно извлечь информацию.
Спасибо, это сработало отлично! Еще один случайный вопрос, поскольку вы кажетесь большим источником знаний в этой области - знаете ли вы, как (надеюсь, легко) изменить протокол передачи сообщений? По умолчанию в примере приложения это UDP, однако я думаю, что это слишком просто, так как фактическое сообщение в GeneralMessage не записано в файле Pcap, который я позже проанализирую. То есть я хотел бы, чтобы скорость автомобиля была видна в этой записи Pcap. Я вижу из демонстрации Pcap, что, возможно, мне может понадобиться использовать ARP. Это возможно?