3

我正在为相当简单的二进制协议编写 Ragel 机器,我在这里展示的是更加简化的版本,没有任何错误恢复,只是为了演示我要解决的问题。

所以,这里要解析的消息是这样的:

<1 byte: length> <$length bytes: user data> <1 byte: checksum>

机器外观如下:

%%{
   machine my_machine;
   write data;
   alphtype unsigned char;
}%%

%%{
   action message_reset {
      /* TODO */
      data_received = 0;
   }

   action got_len {
      len = fc;
   }

   action got_data_byte {
      /* TODO */
   }

   action message_received {
      /* TODO */
   }

   action is_waiting_for_data {
      (data_received++ < len);
   }

   action is_checksum_correct {
      1/*TODO*/
   }


   len = (any);
   fmt_separate_len = (0x80 any);
   data = (any);
   checksum = (any);

   message = 
      (
         # first byte: length of the data
         (len                                   @got_len)
         # user data
         (data       when is_waiting_for_data   @got_data_byte )*
         # place higher priority on the previous machine (i.e. data)
         <: 
         # last byte: checksum
         (checksum   when is_checksum_correct   @message_received)
      ) >to(message_reset)
      ;

   main := (msg_start: message)*;

   # Initialize and execute.
   write init;
   write exec;
}%%

如您所见,首先我们收到代表长度的 1 个字节;然后我们接收data字节,直到我们收到所需的字节数(检查由 完成is_waiting_for_data),当我们收到下一个(额外)字节时,我们检查它是否是正确的校验和(由is_checksum_correct)。如果是,机器将等待下一条消息;否则,这个特定的机器会停止(为了简化图表,我没有故意在这里包含任何错误恢复)。

它的示意图如下所示:

$ ragel -Vp ./msg.rl | dot -Tpng -o msg.png

点击查看图片

如您所见,在状态 1 中,当我们接收用户数据时,条件如下:

0..255(is_waiting_for_data, !is_checksum_correct),
0..255(is_waiting_for_data, is_checksum_correct)

因此,在它冗余调用的每个数据字节上is_checksum_correct,尽管结果根本不重要。

条件应该很简单:0..255(is_waiting_for_data)

如何做到这一点?

4

1 回答 1

2

应该如何is_checksum_correct工作?when根据您发布的内容,这种情况发生在读取校验和之前。我的建议是检查里面的校验message_received和并在那里处理任何错误。这样,您可以摆脱第二个when问题,问题将不再存在。

看起来语义条件是 Ragel 中一个相对较新的特性,虽然它们看起来非常有用,但如果你想要优化代码,它们可能还不够成熟。

于 2016-01-08T18:37:25.927 回答