2

我们有一个通过 MQ 与外部通信的进程。外部系统在大型机(IBM z/OS)上运行,而我们在 CentOS Linux 平台上运行我们的进程。到目前为止,我们从未遇到任何问题。

最近,我们开始接收来自他们的消息,其中嵌入了不可打印的 EBCDIC 字符。他们使用字符作为压缩 ID,长度为 8 个字节。当我们收到它时,它会到达以 UTF (CCSID 1208) 编码的队列。

他们需要返回原始的 8 个字节才能识别我们的响应消息。我正在尝试在 Java 中找到一种解决方案,以便在发送响应之前将 ID 从 UTF 转换回 EBCDIC。

我一直在玩 JTOpen 库,使用 AS400Text 类进行转换。此外,交易对手已向我们发送了 ID 的快照(以字节为单位)。但是,当我比较转换后的字节时,它们与原始消息不同。

有没有人遇到过这个问题?也许我使用了错误的代码页?

感谢您提供的任何意见。

来自交易对手的字节(位置 [5,14]):

00000   F0 40 D9 F0 F3 F0 CB 56--EF 80 04 C9 10 2E C4 D4  |0 R030.....I..DM|

程序输出:

UTF String: [R030ôîÕ؜IDMDHP1027W 0510]
EBCDIC String: [R030ôîÃÃÂIDMDHP1027W 0510]
NATIVE CHARSET - HEX:     [52303330C3B4C3AEC395C398C29C491006444D44485031303237572030353130] 
CP500 CHARSET  - HEX:     [D9F0F3F066BE66AF663F663F623FC9102EC4D4C4C8D7F1F0F2F7E640F0F5F1F0] 

这是一些示例代码:

private void readAndPrint(MQMessage mqMessage) throws IOException {
    mqMessage.seek(150);
    byte[] subStringBytes = new byte[32];
    mqMessage.readFully(subStringBytes);

    String msgId = toHexString(mqMessage.messageId).toUpperCase();

    System.out.println("----------------------------------------------------------------");
    System.out.println("MESSAGE_ID: " + msgId);

    String hexString = toHexString(subStringBytes).toUpperCase();
    String subStr = new String(subStringBytes);
    System.out.println("NATIVE CHARSET - HEX:     [" + hexString + "] [" + subStr + "]");

    // Transform to EBCDIC
    int codePageNumber = 37;
    String codePage = "CP037";

    AS400Text converter = new AS400Text(subStr.length(), codePageNumber);
    byte[] bytesData = converter.toBytes(subStr);
    String resultedEbcdicText = new String(bytesData, codePage);

    String hexStringEbcdic = toHexString(bytesData).toUpperCase();
    System.out.println("CP500 CHARSET  - HEX:     [" + hexStringEbcdic + "] [" + resultedEbcdicText + "]");

    System.out.println("----------------------------------------------------------------");
}
4

2 回答 2

1

如果 MQ 消息具有不同的子消息字段,需要不同的编码,那么这就是您应该如何处理这些消息的方式,即作为单独的消息片段。

但是正如您所描述的那样,整个消息需要在没有转换的情况下被接收。前八个字节需要单独提取和保存。然后可以对消息的其余部分进行编码转换(除非还需要将其他子字段提取为二进制、未转换的字节)。

对于任何返回消息,必须进行相反的转换。可以转换消息的文本部分,然后该子字符串可以在其前面加上原始的 8 个字节。然后可以通过队列将新重建的消息发送回,而无需自动转换。

另一端的合作伙伴未正确使用消息传递产品。(当然,您可能不应该大声说出来。)这样的消息中不应该有任何部分不能自动在两个方向上完好无损地保存下来。对于一个示例方法,它应该表示为更像是 8 字节值的 16 字节十六进制表示,而不是 8 字节二进制字段。在十六进制中,整个路线都不会出现转换问题。

于 2014-03-20T06:06:44.203 回答
0

在我看来,特殊的 8 个字节实际上不是 EBCDIC 字符,而只是 8 个字节的数据。如果是在这种情况下,那么我相信,正如另一个答案所提到的,您应该单独处理这 8 个字节,而不允许它转换为 UTF8,然后再返回 EBCDIC 进行进一步处理。

根据您使用的 EBCDIC 变体,EBCDIC 中的一个字节很可能没有转换为有意义的 UTF-8 字符,因此,您将无法通过将 UTF8 字符转换为您收到的 EBCDIC 来获取原始字节。

在 Google 上的简短搜索给了我几个 EBCDIC 表(例如http://www.simotime.com/asc2ebc1.htm#AscEbcTables)。您可以看到 EBCDIC 中有很多没有分配字符的值。因此,当它们转换为 UTF8 时,您可能不会假设它们中的每一个都会转换为 Unicode 中的不同字符。因此,您提出的处理方式将非常危险且容易出错。

于 2014-03-20T06:24:26.163 回答