为什么我的流被同行关闭?

时间:2012-11-27 17:45:48

标签: c# .net stomp nms apache-nms

我有以下控制台程序在ActiveMQ Stomp服务器上侦听目标(队列或主题,无关紧要),只需将收到的消息记录到控制台:

using System;
using Apache.NMS.Stomp;
using Apache.NMS;
using Apache.NMS.Util;

namespace StompTest
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                var connectionFactory = new ConnectionFactory("stomp:tcp://mybroker:61613");

                var connection = connectionFactory.CreateConnection();
                connection.ExceptionListener += new ExceptionListener(connection_ExceptionListener);
                connection.Start();

                var session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);

                IDestination dest = SessionUtil.GetDestination(session, "queue://MyQueue");

                var consumer = session.CreateConsumer(dest);
                consumer.Listener += new MessageListener(consumer_Listener);

                Console.ReadKey();
            }
            catch (NMSException ex)
            {
                Console.WriteLine("NMSException !! ==> " + ex.Message);
            }
        }

        static void connection_ExceptionListener(Exception exception)
        {
            Console.WriteLine("Exception!! ==> " + exception.ToString());
        }

        static void consumer_Listener(IMessage message)
        {
            var textMessage = message as ITextMessage;
            if (textMessage == null)
                Console.WriteLine("No ITextMessage...");
            else
                Console.WriteLine("Received => " + textMessage.Text);
        }
    }
}

当我启动它时,只要我不断发送消息,它就能正常工作。但是当有30秒的不活动时,我得到一个例外。即使不向队列发送消息,也会发生这种情况:

Exception!! ==> Apache.NMS.Stomp.IOException: Peer closed the stream.
   at Apache.NMS.Stomp.Protocol.StompFrame.ReadLine(BinaryReader dataIn) in c:\d
ev\NMS.Stomp\src\main\csharp\Protocol\StompFrame.cs:line 284
   at Apache.NMS.Stomp.Protocol.StompFrame.ReadCommandHeader(BinaryReader dataIn
) in c:\dev\NMS.Stomp\src\main\csharp\Protocol\StompFrame.cs:line 208
   at Apache.NMS.Stomp.Protocol.StompFrame.FromStream(BinaryReader dataIn) in c:
\dev\NMS.Stomp\src\main\csharp\Protocol\StompFrame.cs:line 197
   at Apache.NMS.Stomp.Protocol.StompWireFormat.Unmarshal(BinaryReader dataIn) i
n c:\dev\NMS.Stomp\src\main\csharp\Protocol\StompWireFormat.cs:line 121
   at Apache.NMS.Stomp.Transport.Tcp.TcpTransport.ReadLoop() in c:\dev\NMS.Stomp
\src\main\csharp\Transport\Tcp\TcpTransport.cs:line 279

从谷歌搜索,并阅读Apache.NMS源代码,我发现它必须与'InactivityMonitor'做一些事情,显然,当我在连接字符串上指定参数transport.useInactivityMonitor=false时,我不知道得到异常,一切都运行良好。

但就我认为我理解的一切而言,不活动监视器有一个目的:确保检测到并正确清理“死”连接。

所以一定有别的错!我在上面的代码中添加了一个简单的控制台跟踪器,这是没有transport.useInactivityMonitor=false参数连接时的输出:

Info: Connecting to: tcp://mybroker:61613/
Debug: Opening socket to: mybroker on port: 61613
Debug: Connected to mybroker:61613 using InterNetwork protocol.
Debug: Creating Inactivity Monitor: 1
Debug: StompWireFormat - Marshaling: ConnectionInfo[ConnectionId=ID:mypc-309
6-634896376801461632-0:0, Host=mybroker, MaxInactivityDuration=30000, ReadChec
kInterval=30000, WriteCheckInterval=10000, MaxInactivityDurationInitialDelay=0,
ClientId=ID:mypc-3096-634896376801461632-1:0, Password=, UserName=]
Debug: StompWireFormat - Writing StompFrame[ Command=CONNECT, Properties={ heart
-beat=10000,30000 client-id=ID:mypc-3096-634896376801461632-1:0 accept-versi
on=1.0,1.1 host=mybroker}, Content=]
Debug: StompWireFormat - Received StompFrame[ Command=CONNECTED, Properties={ ve
rsion=1.1 server=ActiveMQ/5.6.0 session=ID:mypc-3096-634896376801461632-1:0
heart-beat=0,0}, Content=System.Byte[]]
Debug: InactivityMonitor[1]: Read Check time interval: 30000
Debug: InactivityMonitor[1]: Initial Delay time interval: 10000
Debug: InactivityMonitor[1]: Write Check time interval: 10000
Debug: InactivityMonitor[1]: Starting the Monitor Timer.
Debug: StompWireFormat - Received StompFrame[ Command=KEEPALIVE, Properties={},
Content=]
Debug: InactivityMonitor[1]: New Keep Alive Received at -> 18:28:00.419
Debug: StompWireFormat - Marshaling: ConsumerInfo[ConsumerId=ID:mypc-3096-63
4896376801461632-0:0:1:1, Destination=queue://MyQueue, Ack Mode=AutoAcknowledge,
 PrefetchSize=1000, MaximumPendingMessageLimit=0, DispatchAsync=True, Selector=,
 SubscriptionName=, NoLocal=False, Exclusive=False, Retroactive=False, Priority=
0, Transformation]
Debug: StompWireFormat - Writing StompFrame[ Command=SUBSCRIBE, Properties={ id=
ID:mypc-3096-634896376801461632-0:0:1:1 receipt=2 activemq.dispatchAsync=Tru
e activemq.maximumPendingMessageLimit=0 activemq.priority=0 ack=client activemq.
prefetchSize=1000 transformation=jms-xml destination=/queue/MyQueue}, Content=]
Debug: StompWireFormat - Received StompFrame[ Command=RECEIPT, Properties={ rece
ipt-id=2}, Content=System.Byte[]]
Debug: StompWireFormat - Received StompFrame[ Command=KEEPALIVE, Properties={},
Content=]
Debug: InactivityMonitor[1]: New Keep Alive Received at -> 18:28:00.508
Debug: CheckConnection: Timer Elapsed at 27/11/2012 18:28:10
Debug: InactivityMonitor[1]: Message sent since last write check. Resetting flag
.
Debug: InactivityMonitor[1]: A receive is in progress or already failed.
Debug: CheckConnection: Timer Elapsed at 27/11/2012 18:28:20
Debug: InactivityMonitor[1]: No Message sent since last write check. Sending a K
eepAliveInfo.
Debug: InactivityMonitor[1]: A read check is not currently allowed.
Debug: InactivityMonitor[1] perparing for another Write Check
Debug: InactivityMonitor[1] Write Check required sending KeepAlive.
Debug: StompWireFormat - Marshaling: KeepAliveInfo[ commandId = 0, responseRequi
red = False,  ]
Debug: StompWireFormat - Writing StompFrame[ Command=KEEPALIVE, Properties={}, C
ontent=]
Debug: CheckConnection: Timer Elapsed at 27/11/2012 18:28:30
Debug: InactivityMonitor[1]: No Message sent since last write check. Sending a K
eepAliveInfo.
Debug: InactivityMonitor[1]: A read check is not currently allowed.
Debug: InactivityMonitor[1] perparing for another Write Check
Debug: InactivityMonitor[1] Write Check required sending KeepAlive.
Debug: StompWireFormat - Marshaling: KeepAliveInfo[ commandId = 0, responseRequi
red = False,  ]
Debug: StompWireFormat - Writing StompFrame[ Command=KEEPALIVE, Properties={}, C
ontent=]
Debug: Exception received in the Inactivity Monitor: Apache.NMS.Stomp.IOExceptio
n: Peer closed the stream.
   at Apache.NMS.Stomp.Protocol.StompFrame.ReadLine(BinaryReader dataIn) in c:\d
ev\NMS.Stomp\src\main\csharp\Protocol\StompFrame.cs:line 284
   at Apache.NMS.Stomp.Protocol.StompFrame.ReadCommandHeader(BinaryReader dataIn
) in c:\dev\NMS.Stomp\src\main\csharp\Protocol\StompFrame.cs:line 208
   at Apache.NMS.Stomp.Protocol.StompFrame.FromStream(BinaryReader dataIn) in c:
\dev\NMS.Stomp\src\main\csharp\Protocol\StompFrame.cs:line 197
   at Apache.NMS.Stomp.Protocol.StompWireFormat.Unmarshal(BinaryReader dataIn) i
n c:\dev\NMS.Stomp\src\main\csharp\Protocol\StompWireFormat.cs:line 121
   at Apache.NMS.Stomp.Transport.Tcp.TcpTransport.ReadLoop() in c:\dev\NMS.Stomp
\src\main\csharp\Transport\Tcp\TcpTransport.cs:line 279
Exception!! ==> Apache.NMS.Stomp.IOException: Peer closed the stream.
   at Apache.NMS.Stomp.Protocol.StompFrame.ReadLine(BinaryReader dataIn) in c:\d
ev\NMS.Stomp\src\main\csharp\Protocol\StompFrame.cs:line 284
   at Apache.NMS.Stomp.Protocol.StompFrame.ReadCommandHeader(BinaryReader dataIn
) in c:\dev\NMS.Stomp\src\main\csharp\Protocol\StompFrame.cs:line 208
   at Apache.NMS.Stomp.Protocol.StompFrame.FromStream(BinaryReader dataIn) in c:
\dev\NMS.Stomp\src\main\csharp\Protocol\StompFrame.cs:line 197
   at Apache.NMS.Stomp.Protocol.StompWireFormat.Unmarshal(BinaryReader dataIn) i
n c:\dev\NMS.Stomp\src\main\csharp\Protocol\StompWireFormat.cs:line 121
   at Apache.NMS.Stomp.Transport.Tcp.TcpTransport.ReadLoop() in c:\dev\NMS.Stomp
\src\main\csharp\Transport\Tcp\TcpTransport.cs:line 279
Debug: TransportFilter disposing of next Transport: MutexTransport
Debug: TransportFilter disposing of next Transport: InactivityMonitor
Debug: TransportFilter disposing of next Transport: TcpTransport
Info: Closing The Session with Id ID:mypc-3096-634896376801461632-0:0:1
Debug: Closing down the Consumer
Error: Error during session close: Apache.NMS.Stomp.IOException: Channel was ina
ctive for too long: tcp://mybroker:61613/
   at Apache.NMS.Stomp.Connection.Oneway(Command command) in c:\dev\NMS.Stomp\sr
c\main\csharp\Connection.cs:line 539
   at Apache.NMS.Stomp.MessageConsumer.DoClose() in c:\dev\NMS.Stomp\src\main\cs
harp\MessageConsumer.cs:line 252
   at Apache.NMS.Stomp.Session.DoClose() in c:\dev\NMS.Stomp\src\main\csharp\Ses
sion.cs:line 307
Info: Closed The Session with Id ID:mypc-3096-634896376801461632-0:0:1

所以我认为我的客户被经纪人“踢”了,因为他们长时间不活动。但我真的不明白为什么,从上面的日志中,我的客户端实际上正在发送“keepalive”消息。所以它不应该是不活动的。

我没有选择如何继续解决这个问题。如果有人对此有一些了解,那将非常感谢!

更新
版本号:

  • library:Apache.NMS.Stomp v1.5.3
  • 经纪人:Apache ActiveMQ 5.6.0

1 个答案:

答案 0 :(得分:3)

尝试使用stomp 故障转移传输。所以不是......

var connectionFactory = new ConnectionFactory("stomp:tcp://mybroker:61613");

使用...

var connectionFactory = new ConnectionFactory("failover:tcp://mybroker:61613");

现在,不是引发ExceptionListener事件而是由您来整理,传输将自动重新连接。

仅供参考:如果需要在断开连接/重新连接时收到通知,将引发Connection对象上的ConnectionInterruptedListener和ConnectionResumedListener事件。

同时

我建议使用Session.CreateDurableConsumer而不仅仅是Session.CreateConsumer。这样,您就可以在断开连接/重新连接期间丢失任何消息。

希望这有助于某人。