目录
介绍
在代码中支持IBM MQ并非易事。我可以说,主要原因是缺乏示例,非常复杂的配置,缺乏适当和简单的文档,最后但并非最不重要的一点是,IBM本身的用户体验非常糟糕。
背景
为了能够理解此提示,您需要以下内容:
- 基本的编程知识
- 已安装IBM MQ(本文中的信息已在版本 7.5、8.0和9.0上进行了测试)。
- 此代码是使用.NET Framework 4.7.2测试的,但我相信代码在4.5和3.5中可以正常工作。
- 此代码使用IBM MQ DLL的版本8.0.0.5 amqmdnet.dll, amqmdxcs.dll 进行了测试。
使用代码
配置——正常模式
在开始代码之前,我们需要启动IBM MQ的正确配置,最好和最简单的方法是通过命令。有很多方法可以配置它,所以如果你更喜欢另一种方式,没关系,只要你知道它工作正常。此外,下面的许多命令似乎没有必要。
请注意,以下配置不适用于生产服务器。***
在开始使用Ibm Mq配置之前,让我们创建一个新的Windows用户并将其命名为 mquser。 此用户必须是组“Mqm”的成员。此组将在安装IBM MQ后可用。
创建一个名为QM的新队列管理器:
crtmqm QM
启动队列管理器:
strmqm QM
启动MQSC以执行队列管理器的命令:
runmqsc QM
// Expected Output:
// 5724-H72 (C) Copyright IBM Corp. 1994, 2011. ALL RIGHTS RESERVED.
// Starting MQSC for queue manager QM.
创建名称为(Queue1)的新本地队列:
DEFINE QLOCAL (QUEUE1)
// Expected Output:
// 1 : DEFINE QLOCAL (QUEUE1)
// AMQ8006: WebSphere MQ queue created.
禁用CHLAUTH规则:
ALTER QMGR CHLAUTH (DISABLED)
// Expected Output:
// 2 : ALTER QMGR CHLAUTH (DISABLED)
// AMQ8005: WebSphere MQ queue manager changed
创建一个带有名称CHANNEL1的新频道,并将MCAUSER的值设置为我们的用户MQUser:
DEFINE CHANNEL (CHANNEL1) CHLTYPE (SVRCONN) TRPTYPE (TCP) MCAUSER('MQUser')
// Expected Output:
// 3 : DEFINE CHANNEL (CHANNEL1) CHLTYPE (SVRCONN) TRPTYPE (TCP)
// AMQ8014: WebSphere MQ channel created.
创建侦听器:
DEFINE LISTENER (LISTENER1) TRPTYPE (TCP) CONTROL (QMGR) PORT (1414)
// Expected Output:
// 4 : DEFINE LISTENER (LISTENER1) TRPTYPE (TCP) CONTROL (QMGR) PORT (1414)
// AMQ8626: WebSphere MQ listener created.
启动我们的侦听器:
START LISTENER (LISTENER1)
// Expected Output:
// 5 : START LISTENER (LISTENER1)
// AMQ8021: Request to start WebSphere MQ listener accepted.
最后一个命令,关闭命令:
end
// Expected Output:
// 6 : end
// 6 MQSC commands read.
// No commands have a syntax error.
// All valid MQSC commands were processed.
快速连接测试
使用以下命令,您可以轻松连接到IBM MQ,请注意以下几点:
- UTF-8不是必须的,您可以使用UTF-16。
- 如果需要,许多未提及的可选参数(下面的示例)是对象queueMessage的属性:
- CorrelationId
- MessageId
- ReplyToQueueName
- 该代码将键入IBM MQ错误代码。可以在IBM网站上找到错误代码的完整列表。
- 我们的配置中不需要用户名和密码,如果需要,请取消注释用户名/密码分配。
using IBM.WMQ;
using System;
using System.Collections;
using System.Text;
namespace MQTest
{
class Program
{
static void Main(string[] args)
{
string strQueueManagerName = "QM";
string strChannelName = "CHANNEL1";
string strQueueName = "QUEUE1";
string strServerName = "127.0.0.1";
int intPort = 1414;
string strMsg = "Hello IBM, this is a message";
Hashtable queueProperties = new Hashtable
{
{ MQC.HOST_NAME_PROPERTY, strServerName },
{ MQC.CHANNEL_PROPERTY, strChannelName },
{ MQC.PORT_PROPERTY, intPort },
{ MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED }
};
//Set Username
//MQEnvironment.UserId = "User";
//Set Passowrd
//MQEnvironment.Password = "123";
//Define a Queue Manager
try
{
MQQueueManager myQM = new MQQueueManager
(strQueueManagerName, queueProperties);
//Define a Message
MQMessage queueMessage = new MQMessage();
queueMessage.Format = MQC.MQFMT_STRING;
queueMessage.CharacterSet = Encoding.UTF8.CodePage;
queueMessage.Write(Encoding.UTF8.GetBytes(strMsg));
//Define a Queue
var queue = myQM.AccessQueue
(strQueueName, MQC.MQOO_OUTPUT + MQC.MQOO_FAIL_IF_QUIESCING);
MQPutMessageOptions queuePutMessageOptions = new MQPutMessageOptions();
queue.Put(queueMessage, queuePutMessageOptions);
queue.Close();
Console.WriteLine("Success");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
}
}
配置——SSL
现在,让我们开始复杂的部分——在IBM MQ和客户机代码之间配置安全连接。在我们开始之前,您需要了解许多重要注意事项:
- 有两种方法可以使用SSL连接到IBM MQ,客户端共享的第一种方法是其证书。另一种方法是没有客户端共享证书。
- 此代码使用所谓的“匿名IBM MQ连接”通过SSL连接到 IBM MQ。更多细节可以在这里找到。在此模式下,客户端不会发送其证书。
- 在与IBM合作期间,我发现IBM MQ程序集中定义的许多参数都没有使用,甚至毫无用处。我可能弄错了,但所有证据都表明并非如此。通过这篇文章,我将在每个参数旁边添加单词(无用),也许有人会在本文的评论中向我和其他所有人解释这一点。
要使用SSL启动SSL配置,让我们返回到命令提示符:
1、导航到队列管理器文件夹下的SSL文件夹,可以在安装位置下找到该文件夹,默认情况下为:“C:\Program Files (x86)\IBM\WebSphere MQ\Qmgrs\QM\ssl”:
pushd "C:\Program Files (x86)\IBM\WebSphere MQ\Qmgrs\QM\ssl"
2、执行命令以创建名称与您的队列管理器名称和密码12345相匹配的ssl存储库。
runmqckm -keydb -create -db QM.kdb -pw 12345 -type cms -stash
3、让我们创建一个自签名证书,以便我们可以将其用于测试:
runmqckm -cert -create -db QM.kdb -dn "CN=QM,OU=QM,O=SunJ,L=Amman,S=Amman,C=JO"
-pw 12345 -label ibmwebspheremqqm -size 2048 -expire 365 -sig_alg SHA256_WITH_RSA
注意以下几点非常重要:
- QM.kdb是我们在步骤2中创建的存储库,它与队列管理器名称匹配。
- 在命令中的-label必须是ibmwebspheremq,后面跟着小写的QM队列管理器名称。
- 所有证书参数(如“L=, S=, C=”)都可以根据需要进行更改。
- 剩余的参数必须保持原样,除非您知道自己到底在做什么。
4、提取证书?
如上所述,我们不会在此处提取证书,我们将在不从客户端发送证书的情况下进行连接。如果您想使用其他连接方式,一个非常重要的注意事项是:
1、IBM MQ客户机组件转到可信存储区,并且仅加载一个证书,该证书的名称ibmwebspheremq后跟以小写形式运行代码的本地机器用户。这会将我带到IBM MQ程序集中的第一个(无用的)参数,即MQEnvironment.CertificateLabel或MQC.label。
这对我来说很奇怪...我什至反编译了IBM程序集以查看它是否实际使用,下面是用于加载证书的唯一代码。它可能是为了将来使用而存在的,但可以肯定的是,它非常令人困惑和误导。
RemoteCertificateValidationCallback(true),
new LocalCertificateSelectionCallback(this.FixClientCertificate));
var storeLocation = StoreLocation.LocalMachine;
X509Store x509Store = new X509Store(StoreName.My, storeLocation);
x509Store.Open(OpenFlags.OpenExistingOnly);
X509Certificate2Collection x509Certificate2Collection =
new X509Certificate2Collection();
X509Certificate2Enumerator enumerator =
x509Store.Certificates.GetEnumerator();
var clientCertName =
string.Concat("ibmwebspheremq", Environment.UserName.ToLower());
while (enumerator.MoveNext())
{
X509Certificate2 current = enumerator.Current;
if (current.FriendlyName.ToLower() != clientCertName)
{
continue;
}
x509Certificate2Collection.Add(current);
}
有关此内容的更多详细信息,请访问 IBM WebSphere MQ客户机下的IBM网站。
2、正如您在IBM代码中看到的那样,它正在查找友好名称以查找证书,如果您使用该runmqckm -cert -extract命令,该名称将为空。我的建议是使用PowerShell验证你的许可证友好名称并进行更改。否则,您的代码不会拾取它。
5、将队列管理器配置为使用SSL:
- 右键单击队列管理器,然后选择属性。
- 从左侧菜单中,选择 SSL。
- 在SSL存储库中,设置我们在第一步“QM.kdb”中创建的存储库的位置和名称,但不要添加扩展名。最后的路径将是 C:\Program Files (x86)\IBM\WebSphere MQ\qmgrs\QM\ssl\QM。一个非常常见的错误是添加扩展或忘记存储库的名称,不幸的是,IBM WebSphere 根本不会通知您输入了无效的密钥。
4. 现在单击“确定”,然后单击“是”进入确认对话框。
6、最后一步是配置您的频道:
- 右键单击您的频道,然后单击属性。
- 同样,从右侧菜单中,选择 SSL。
- 我们需要将SSL密码规格值设置为“TLS_RSA_WITH_AES_128_CBC_SHA256”,但在我们这样做之前,我们带来了第二个(无用的)参数“MQEnvironment.SSLCipherSpec”或“MQC.SSL_CIPHER_SPEC_PROPERTY”。
您可以在代码中将此参数设置为您想要的任何参数,它不会有任何区别。实际上,客户端将使用组策略中设置的Windows默认密码规范,该规范通常默认为TLS_RSA_WITH_AES_128_CBC_SHA256。如果不是这种情况,您可以使用以下步骤对其进行配置:
- 从组策略管理控制台中,转到“计算机配置”>“管理模板”>“网络”>”SSL配置设置”。
- 双击“SSL密码套件顺序”,然后单击“已启用”选项。
- 右键单击“SSL密码套件”框,然后从弹出菜单中选择“全选”。
- 将 SSL密码套件中的列表替换为TLS_RSA_WITH_AES_128_CBC_SHA256。
- 单击确定或应用。
这甚至比证书标签更奇怪——您可以看到IBM网站上的许多示例显示,您需要在通道中配置代码时设置代码中的值。但它实际上所做的只是告诉客户端使用SSL代码。因此,想象一下这是一个称为“使用SSL”的标志。
您可以尝试在代码和通道SSL配置中将其更改为TLS_RSA_WITH_AES_256_CBC_SHA256,您将在事件查看器中收到以下错误。
1、最后一步,正如我们之前提到的,我们的客户端代码不会从其端发送证书,因此我们需要将 SSL身份验证值设置为 可选。
2、单击“确定”。
修改代码以支持SSL
我们的代码将不再起作用,因此让我们再添加几行来使用SSL修改我们的代码,我们需要添加的只是:
MQEnvironment.SSLCipherSpec = "TLS_RSA_WITH_AES_256_CBC_SHA256";
正如我之前提到的,虽然设置密码规范SSLCipherSpec是无用的,但它可以作为打开SSL模式的标志。
完整的最终代码
using IBM.WMQ;
using System;
using System.Collections;
using System.Text;
namespace MQTest
{
class Program
{
static void Main(string[] args)
{
string strQueueManagerName = "QM";
string strChannelName = "CHANNEL1";
string strQueueName = "QUEUE1";
string strServerName = "127.0.0.1";
int intPort = 1414;
string strMsg = "Hello IBM, this is a message";
//Enable SSL
MQEnvironment.SSLCipherSpec = "TLS_RSA_WITH_AES_256_CBC_SHA256";
Hashtable queueProperties = new Hashtable
{
{ MQC.HOST_NAME_PROPERTY, strServerName },
{ MQC.CHANNEL_PROPERTY, strChannelName },
{ MQC.PORT_PROPERTY, intPort },
{ MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED }
};
//Set Username
//MQEnvironment.UserId = "User";
//Set Passowrd
//MQEnvironment.Password = "123";
//Define a Queue Manager
try
{
MQQueueManager myQM =
new MQQueueManager(strQueueManagerName, queueProperties);
//Define a Message
MQMessage queueMessage = new MQMessage();
queueMessage.Format = MQC.MQFMT_STRING;
queueMessage.CharacterSet = Encoding.UTF8.CodePage;
queueMessage.Write(Encoding.UTF8.GetBytes(strMsg));
//Define a Queue
var queue = myQM.AccessQueue
(strQueueName, MQC.MQOO_OUTPUT + MQC.MQOO_FAIL_IF_QUIESCING);
MQPutMessageOptions queuePutMessageOptions = new MQPutMessageOptions();
queue.Put(queueMessage, queuePutMessageOptions);
queue.Close();
Console.WriteLine("Success");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
}
}
兴趣点
IBM MQ是已创建的领先队列系统之一,也可能是最常用的队列系统。然而,IBM失败得很惨,因为它使本应非常简单的工作变成了一个漫长而艰难的试错过程。
在IBM MQ WebSphere上缺乏适当的验证、可以通过特殊命令行“例如主块规则”看到的隐藏属性和规则与已发布程序集中未使用的误导性变量和配置之间。
根据我在使用IBM时的发现,我确信还有许多其他参数也可以被视为未使用。虽然另一方面,所有这些都可能是我这边的错误。
https://www.codeproject.com/Tips/5268164/Connecting-to-IBM-MQ-with-SSL