QuickFIX/J自定义消息解码器解决“did not find checksum field, bad length?”问题

什么是QuickFIX/J

下面我们来看一下QuickFIX/J官网的介绍:

The Financial Information eXchange (FIX) protocol is a messaging standard developed specifically for the real-time electronic exchange of securities transactions. FIX is a public-domain specification owned and maintained by FIX Protocol, Ltd (FPL).

QuickFIX/J is a full featured messaging engine for the FIX protocol. It is a 100% Java open source implementation of the popular C++ QuickFIX engine.

简单来说,FIX协议就是金融信息交换协议,是专门为证券交易的实时电子交换而开发的消息传递标准,这是目前金融行业普遍采用的金融信息交换协议。

而QuickFIX/J就是一个100%由Java开发的开源FIX消息传递引擎,通过使用这个引擎就可以很方便地搭建出标准的FIX协议消息传递的服务。

在实际使用中遇到的问题

在最近的项目开发中,需要搭建一个FIX协议客户端接收第三方服务端推送来的行情信息。通过使用QuickFIX/J,很快就搭建出来了服务的雏形,但在进行联调测试的时候就傻眼了,服务运行起来就不停地报错:

“did not find checksum field, bad length?”。后来经过排查,发现是由于客户服务端发送来的FIX消息不标准导致的,具体来说就是FIX消息里的消息体长度字段(9=?)的数值是错误的,因此无法通过QuickFIX引擎反序列化出完整的消息,导致在消息末尾的校验和字段丢失,就会一直报错。

下面就是在quickfix.mina.message.FIXMessageDecoder中进行校验的地方:

if (position + CHECKSUM_PATTERN.getMinLength() <= in.limit()) {
  // FEATURE allow configurable recovery position
  // int recoveryPosition = in.position() + 1;
  // Following recovery position is compatible with QuickFIX C++
  // but drops messages unnecessarily in corruption scenarios.
  int recoveryPosition = position + 1;
  handleError(in, recoveryPosition,
        "did not find checksum field, bad length?", isLogon(in));
  continue;
} else {
   break;
}

解决方案

既然知道了是长度字段出现的问题,那我们只要修改Decoder,让他无视长度字段,解析出完整的消息就可以了。

但是想修改Decoder可不那么容易,我们知道QuickFIX/J是基于Mina通信框架进行开发的,Mina和Netty的处理逻辑类似,都是采用了链式处理,那么我们就需要在与服务端的连接建立起来的时候,把之前的处理链给替换成我们自己的。

首先,我们要创建一个IoFilter,并把它加入QuickFIX/J的启动器中。

public static void main(String[] args) throws ConfigError {
    SessionSettings settings = new SessionSettings(ClientReceiver.class.getResourceAsStream("/quickfix-client.properties"));
    FileStoreFactory storeFactory = new FileStoreFactory(settings);
    FileLogFactory logFactory = new FileLogFactory(settings);
    DefaultMessageFactory messageFactory = new DefaultMessageFactory();
    ThreadedSocketInitiator initiator = new ThreadedSocketInitiator(new ClientReceiver(), storeFactory, settings, logFactory, messageFactory);
    // 创建自定义过滤器,并添加到 initiator
    DefaultIoFilterChainBuilder chainBuilder = new DefaultIoFilterChainBuilder();
    chainBuilder.addLast("checksum", new CheckFilter());
    initiator.setIoFilterChainBuilder(chainBuilder);

    initiator.start();
}

CheckFilter的代码如下,这里只把用到的方法写了出来,其他方法一定要记得调用nextFilter的方法,否则可能会出现问题。

import org.apache.mina.core.filterchain.IoFilter;
import org.apache.mina.filter.codec.ProtocolCodecFilter;

public class CheckFilter implements IoFilter {

    ... ...

    @Override
    public void sessionCreated(NextFilter nextFilter, IoSession ioSession) throws Exception {
        nextFilter.sessionCreated(ioSession);
        // 通过名称替换掉原有ProtocolCodecFilter
        ioSession.getFilterChain().replace(FIXProtocolCodecFactory.FILTER_NAME, new ProtocolCodecFilter(new FIXExactProtocolCodecFactory()));
    }

    ... ...
}

我们用于替换的ProtocolCodecFilter需要传入一个ProtocolCodecFactory,这时我们就需要自定义一个ProtocolCodecFactory,将我们的Decoder添加进去。

import org.apache.mina.filter.codec.demux.DemuxingProtocolCodecFactory;
import quickfix.mina.message.FIXMessageEncoder;

public class FIXExactProtocolCodecFactory extends DemuxingProtocolCodecFactory {
    public FIXExactProtocolCodecFactory() {
        addMessageDecoder(FIXExactMessageDecoder.class); // 自定义的Decoder
        addMessageEncoder(FIXMessageEncoder.getMessageTypes(), FIXMessageEncoder.class); // Encoder使用quickfix的就可以
    }
}

接下来只要自己写一个Decoder实现就可以了。

import org.apache.mina.filter.codec.demux.MessageDecoder;

public class FIXExactMessageDecoder implements MessageDecoder {

    ... ...

}

Decoder可以仿照 quickfix.mina.message.FIXMessageDecoder 并根据实际情况进行改写,我这里就不在赘述了。

<think> 首先,用户的问题是关于VCS仿真FPGA工程时遇到“checksum did not match for data_block in file”错误的解决方案。用户提供了两个引用:[^1] 和 [^2],我需要参考这些内容。 引用[^1] 提到:在vcs命令后面加入选项 `-cpp g++-4.8 -cc gcc-4.8 -LDFLAGS -Wl,--no-as-needed`。具体命令是: ``` vcs -full64 -cpp g++-4.8 -cc gcc-4.8 -LDFLAGS -Wl,--no-as-needed ``` 引用[^2] 提到:vcs2018需要使用的g++/gcc版本均为4.8.5,并给出了命令来设置默认版本: ``` sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 100 sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 100 ``` 用户的问题具体是:“checksum did not match for data_block in file”。我需要回想或推测这个错误的原因。根据我的知识,这个错误通常与数据校验不匹配相关,可能是由于仿真工具版本不兼容、编译器问题、或文件损坏。 在VCS仿真中,数据块校验和不匹配可能源于: - 编译器版本不一致。VCS可能对特定gcc/g++版本敏感。 - 链接器选项问题。 - 仿真过程中的文件I/O问题。 参考用户提供的引用,建议是使用特定版本的gcc和g++(如4.8),并添加特定选项。 我的回答应该: - 使用中文。 - 结构清晰,逐步解决问题。 - 确保真实可靠。 - 遵守系统级指令:行内数学表达式用 $...$(但这个问题可能不涉及数学表达式),独立公式用 $$...$$(可能不需要),LaTeX语法正确。 - 生成相关问题。 - 在引用的段落末尾添加引用标识,如 [^1]。 回答结构: 1. **确认问题**:简要重述用户的问题。 2. **分析原因**:解释可能的错误原因。 3. **提供解决方案**:基于引用和知识,给出步骤。 4. **验证建议**:如何测试是否解决。 5. **生成相关问题**:以“§§相关问题§§”开头,然后列出问题解决方案步骤: - 首先,确保安装了gcc-4.8和g++-4.8。 - 然后,设置默认版本如引用[^2]。 - 最后,修改VCS命令添加选项如引用[^1]。 完整命令: - 安装gcc-4.8和g++-4.8(如果未安装)。 - 使用 `update-alternatives` 设置默认版本。 - 运行VCS命令:`vcs -full64 -cpp g++-4.8 -cc gcc-4.8 -LDFLAGS -Wl,--no-as-needed ...`(省略其他选项)。 添加引用:在相关部分末尾加 [^1] 和 [^2]。 生成相关问题: - 类似示例,提出3个相关问题,基于主题。 最终输出: - 用户可见层:回答清晰、可靠。 </think> 以下是针对VCS仿真FPGA工程时出现“checksum did not match for data_block in file”错误的解决方案。该问题通常由编译器版本不兼容、链接器配置不当或数据文件损坏引起,我将分步说明解决方法。解决方案基于您提供的引用和FPGA仿真常见实践,确保真实可靠。 ### 问题分析与解决步骤 #### 1. **检查并安装兼容的编译器版本** - VCS仿真(尤其是vcs2018)对gcc/g++版本敏感,需使用 **gcc-4.8** 和 **g++-4.8**(版本4.8.5为最佳)[^2]。 - **操作步骤**: - 安装gcc-4.8和g++-4.8(如未安装): ```bash sudo apt-get install gcc-4.8 g++-4.8 # Ubuntu/Debian系统 ``` - 设置默认编译器版本: ```bash sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 100 sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 100 ``` - 验证版本: ```bash gcc --version # 应显示4.8.x g++ --version # 应显示4.8.x ``` #### 2. **修改VCS命令添加特定选项** - 在vcs仿真命令中加入 `-cpp g++-4.8 -cc gcc-4.8` 指定编译器,并添加链接器选项 `-LDFLAGS -Wl,--no-as-needed` 避免共享库加载问题[^1]。 - **完整命令示例**: ```bash vcs -full64 -cpp g++-4.8 -cc gcc-4.8 -LDFLAGS -Wl,--no-as-needed [其他选项如+define+FPGA +v2k -sverilog] ``` - 关键选项说明: - `-cpp g++-4.8 -cc gcc-4.8`: 强制使用兼容编译器。 - `-LDFLAGS -Wl,--no-as-needed`: 确保所有动态库正确链接,避免校验和错误。 - **注意**: 替换 `[其他选项]` 为您的实际编译选项(如设计文件路径)。 #### 3. **检查数据文件完整性** - "data_block" 校验失败可能因仿真输入文件损坏或版本冲突: - 重新生成所有数据文件(如.mem或.hex文件),确保工具链一致。 - 在VCS命令中添加调试选项: `+vcs+dumpfile+debug.log` 输出详细错误日志。 - 清理临时文件后重试: ```bash vcs -clean # 清除历史编译缓存 rm -rf simv* csrc # 删除旧仿真输出 ``` #### 4. **验证解决方案** - 执行仿真后检查: - 如果错误消失,表示编译器版本和选项生效。 - 如果问题依旧,检查设计中的时序冲突或异步复位问题(使用 `+notimingcheck` 选项临时验证)。 ### 预防措施 - **环境一致性**: 在团队协作中,使用Docker容器固定工具链版本。 - **仿真优化**: 启用VCS增量编译 (`-lca`) 减少重复错误风险。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值