热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

对ActiveMQ.NET1.1.0组件接受中文信息乱码的修复

最近在使用ApacheActiveMQ消息队列做一些工作,在使用的时候,发现发送消息的内容是中文时,获得消息时,获得的是乱码。发送和接收我使用的是ActiveMQ.NET1.1.0组件。

最近在使用 Apache ActiveMQ 消息队列做一些工作,在使用的时候,发现发送消息的内容是中文时,获得消息时,获得的是乱码。

发送和接收我使用的是 ActiveMQ .NET 1.1.0 组件。

分析原因进去后,发现是这个开源组件的 Apache.NMS.ActiveMQ 组件的 /Apache.NMS.ActiveMQ-1.1.0-src/src/main/csharp/Transport/Stomp/StompWireFormat.cs 文件对应的 StompWireFormat 类的 public Object Unmarshal(BinaryReader dis) 方法中有错误。

错误在该文件的 166 行

之前的错误代码如下:

public Object Unmarshal(BinaryReader dis)
{
string command;
do {
command = ReadLine(dis);
}
while (command == "");

Tracer.Debug("<<<" + command);

IDictionary headers = new Hashtable();
string line;
while ((line = ReadLine(dis)) != "")
{
int idx = line.IndexOf(':');
if (idx > 0)
{
string key = line.Substring(0, idx);
string value = line.Substring(idx + 1);
headers[key] = value;

Tracer.Debug("<<<" + key + " = " + value);
}
else
{
// lets ignore this bad header!
}
}
byte[] cOntent= null;
string length = ToString(headers["content-length"]);
if (length != null)
{
int size = Int32.Parse(length);
cOntent= dis.ReadBytes(size);
// Read the terminating NULL byte for this frame.
int nullByte = dis.Read();
if(nullByte != 0)
{
Tracer.Debug("<<<");
}
}
else
{
MemoryStream ms = new MemoryStream();
int nextChar;
while((nextChar = dis.Read()) != 0)
{
if( nextChar <0 )
{
// EOF ??
break;
}
ms.WriteByte((byte)nextChar);
}
cOntent= ms.ToArray();
}
Object answer = CreateCommand(command, headers, content);
Tracer.Debug("<<<" + answer);
return answer;
}

internal String ReadLine(BinaryReader dis)
{
MemoryStream ms = new MemoryStream();
while (true)
{
int nextChar = dis.Read();
if (nextChar <0)
{
throw new IOException("Peer closed the stream.");
}
if( nextChar == 10 )
{
break;
}
ms.WriteByte((byte)nextChar);
}
byte[] data = ms.ToArray();
return encoding.GetString(data, 0, data.Length);
}

这个源代码文件可以在下面地址看到:

https://svn.apache.org/repos/asf/activemq/activemq-dotnet/Apache.NMS.ActiveMQ/tags/1.1.0/src/main/csharp/Transport/Stomp/StompWireFormat.cs

正确的代码如下:

internal string ReadLine(NetworkStream ns)
{
MemoryStream ms = new MemoryStream();
while (true)
{
int nextChar = ns.ReadByte();
if (nextChar <0)
{
throw new IOException("Peer closed the stream.");
}
if (nextChar == 10)
{
break;
}
ms.WriteByte((byte)nextChar);
}
byte[] data = ms.ToArray();
return encoding.GetString(data, 0, data.Length);
}
public Object Unmarshal(BinaryReader dis)
{
NetworkStream ns = dis.BaseStream as NetworkStream;
if (ns == null) return null;
if (!ns.CanRead) return null;

// 读取 command 信息
string command;
do
{
command = ReadLine(ns);
}
while (command == "");

Tracer.Debug("<<<" + command);

// 读取 header 信息
IDictionary headers = new Hashtable();
string line;
while ((line = ReadLine(ns)) != "")
{
int idx = line.IndexOf(':');
if (idx > 0)
{
string key = line.Substring(0, idx);
string value = line.Substring(idx + 1);
headers[key] = value;

Tracer.Debug("<<<" + key + " = " + value);
}
else
{
// lets ignore this bad header!
}
}

// 读取消息内容
MemoryStream ms = new MemoryStream();
do
{
int t = ns.ReadByte();
if (t <= 0) break;
ms.WriteByte((byte)t);
}
while (ns.DataAvailable);

byte[] cOntent= ms.ToArray();

Object answer = CreateCommand(command, headers, content);
Tracer.Debug("<<<" + answer);
return answer;
}

之前的错误代码,在发送“a1郭红俊b2” 这样的中英文数字混合的信息时,发送时,发送的 byte数组 信息如下:

97,49,233,131,173,231,186,162,228,191,138,98,50

接受时,接受到的 byte 数组信息就变成了

97,49,239,191,189,239,191,189,98,50

 

原先的 BinaryReader dis 其实是个这个开源组件自己写的派生自BinaryReader 的  OpenWireBinaryReader 类。这个类有很多不完善的地方。

这部分的逻辑可以在 TcpTransport 类的下面调用中看到

private readonly Socket socket;
private BinaryReader socketReader;

socketReader = new OpenWireBinaryReader(new NetworkStream(socket));

原先的 OpenWireBinaryReader  不完善的地方:

1、传送中文时,会丢数据;ms.WriteByte((byte)nextChar); 会让本来nextChar对应的 byte 数组,只取了数组的第一项,数组的其他项则丢失了;

2、编码混乱,unicode 和 utf-8 转换有问题。

 

参考资料:

Apache ActiveMQ
http://activemq.apache.org/

ActiveMQ .NET
http://activemq.apache.org/nms/


推荐阅读
  • 怎么在PHP项目中实现一个HTTP断点续传功能发布时间:2021-01-1916:26:06来源:亿速云阅读:96作者:Le ... [详细]
  • 本文介绍了在Android开发中使用软引用和弱引用的应用。如果一个对象只具有软引用,那么只有在内存不够的情况下才会被回收,可以用来实现内存敏感的高速缓存;而如果一个对象只具有弱引用,不管内存是否足够,都会被垃圾回收器回收。软引用和弱引用还可以与引用队列联合使用,当被引用的对象被回收时,会将引用加入到关联的引用队列中。软引用和弱引用的根本区别在于生命周期的长短,弱引用的对象可能随时被回收,而软引用的对象只有在内存不够时才会被回收。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • Linux磁盘的分区、格式化的观察和操作步骤
    本文介绍了如何观察Linux磁盘的分区状态,使用lsblk命令列出系统上的所有磁盘列表,并解释了列表中各个字段的含义。同时,还介绍了使用parted命令列出磁盘的分区表类型和分区信息的方法。在进行磁盘分区操作时,根据分区表类型选择使用fdisk或gdisk命令,并提供了具体的分区步骤。通过本文,读者可以了解到Linux磁盘分区和格式化的基本知识和操作步骤。 ... [详细]
  • 本文介绍了三种方法来实现在Win7系统中显示桌面的快捷方式,包括使用任务栏快速启动栏、运行命令和自己创建快捷方式的方法。具体操作步骤详细说明,并提供了保存图标的路径,方便以后使用。 ... [详细]
  • 开发笔记:Java是如何读取和写入浏览器Cookies的
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java是如何读取和写入浏览器Cookies的相关的知识,希望对你有一定的参考价值。首先我 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 本文介绍了在Windows系统上使用C语言命令行参数启动程序并传递参数的方法,包括接收参数程序的代码和bat文件的编写方法,同时给出了程序运行的结果。 ... [详细]
  • 本文介绍了一种轻巧方便的工具——集算器,通过使用集算器可以将文本日志变成结构化数据,然后可以使用SQL式查询。集算器利用集算语言的优点,将日志内容结构化为数据表结构,SPL支持直接对结构化的文件进行SQL查询,不再需要安装配置第三方数据库软件。本文还详细介绍了具体的实施过程。 ... [详细]
  • MySQL数据库锁机制及其应用(数据库锁的概念)
    本文介绍了MySQL数据库锁机制及其应用。数据库锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中,数据是一种供许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决的问题。MySQL的锁机制相对简单,不同的存储引擎支持不同的锁机制,主要包括表级锁、行级锁和页面锁。本文详细介绍了MySQL表级锁的锁模式和特点,以及行级锁和页面锁的特点和应用场景。同时还讨论了锁冲突对数据库并发访问性能的影响。 ... [详细]
  • 本文详细介绍了Python open()函数的用法,包括文件操作的流程和具体的打开模式。通过该函数,可以打开文件并进行读取、写入等操作。同时,还介绍了文件路径的两种形式和不同的打开模式。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
author-avatar
逝去成回忆2502920253
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有