微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用观察者模式发送和接收多个不同的二进制消息的方法

如何解决使用观察者模式发送和接收多个不同的二进制消息的方法

我有N种不同的二进制消息,让我们将其称为 BM 。这些消息是通过不同的链接(串行,wifi,以太网)发送和接收的。它们有一些标头字节(例如消息ID,数据长度和末尾的校验和)。我坚持如何最好地从流中读取消息,以及在通知任何观察者特定的BM时应发送什么对象/数据。以下是其布局的示例。

// Base class for all N type messages to inherit from.
// **A BM does not kNow about the header bytes,or checksum algorithms,it 
// doesnt care. These are handled by the BMStream**
class BM {
public:
  // Responsible for taking the data fields of a BM,and packing them into buf
  virtual void Serialize(std::uint8_t* buf) = 0;
  // Responsible for taking fields out of buf
  virtual void Deserialize(std::uint8_t* buf) = 0;
  // Each BM is a fixed or kNown length (number of bytes)
  virtual std::uint64_t Length() = 0;
};
// Example one of N messages
class MyMessage1 : public BM {
private:
  std::uint16_t count;
  std::uint64_t time;
public:
  // Each BM gets a unique ID,this is how they are identified in a binary stream
  static const std::uint16_t MSG_ID = 123;

  // This would convert fields count and time into byte messages,not showing it here
  // but it would look like buf[0] = (count & 0x00FF << 8),etc.
  void Serialize(std::uint8_t* buf);
  // Similarly would take data out of buf and assign to the fields
  // count = buf[0] << 8 | buf[1]
  void Deserialize(std::uint8_t* buf);
  // Would return 10 (8 bytes for time,2 for count).
  std::uint64_t Length();
};

这是我在设计BMStream时经常遇到的问题 然后是一个BM流,它在自己的线程上运行以获取BM并将其写入,从流中读取任何传入的消息并通知观察者。 MyMessage1的观察者需要MyMessage1对象,而不是BM。但是为了做到这一点,BMStream需要知道MSG_ID1对应于MyMessage1(MSG_ID可能是0xFF23或其他)。它不应该真正在乎,它只是在乎从流中读取和写入有效的BM。 编写似乎是最容易的原因,因为MyMessage1可以安全地“广播”到BM。这对我来说最令人困惑或困难的阅读。

class BMStream {
public:
  // Internally write() adds to a queue of outgoing messages since its running on a separate thread,will just continuously check for outgoing messages
  // On writing a BM it will add any header bytes,ask the BM for its length and ID,serialize the BM,compute CRC and send out of the link.
  void write(const BM& bm);
  // Registering for a new type of BM. Internally BMStream keeps a map of MSG_ID's 
  // and observers interested in the corresponding message. So if BM stream reads a 
  // valid BM (from the header,crc,msgiD) and msgiD matches id,it will call back observer.
  void Register(std::uint16_t id,BMObserver* observer);
};

// Move involved setup (port numbering,IP address,etc.)
BMStream my_stream;
MyMessage1 my_message1;
// Some setting of fields of my_message1
my_stream.write(my_message1);
BMObserver i_want_message1;
// Register for BM's of ID 123
my_stream.Register(MyMessag1.MSG_ID,&i_want_message1);
// ... Some time later ...
// my_stream has read a series of bytes from a stream (file for example)
// These bytes have the valid header bytes,and the type is MSG_ID1
// What does it do? 
// It has these bytes in a buffer we kNow are MSG_ID1. i_want_message1 only wants a MyMessage1,// which has fields count and time,none of the extra stuff needed for serializing (header,etc.)
// That means BMStream needs to kNow how to cast?? (not sure if thats correct term) 
// MSG_ID1s into MyMessage1. 
// This seems do-able from a table of function pointers,but then how do you 
// send that data through a generic observers/callbacks? One that works for 
// MyMessage2,MyMessage100,etc. I have only seen function pointer tables of all the 
// the same type (void*,int*,etc.)

我还要注意,MSG_ID是一个16位int,因此从技术上讲,可能的消息为0到65535。这并不意味着所有消息都将在运行时存在。一个实例可能有消息0/1000/24534,而另一个实例可能有0/435/47467,以此类推。这就是为什么我采用观察者模式并在地图中将观察者注册到ID的原因,以避免在分配时分配65535表可能只需要10条消息(取决于程序/应用程序)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。