最後編輯/結論的Netty的messageReceived()將不會被調用與長壽連接
一段時間後,這是無關的網狀問題,仍然很難調試。 messageReceived中的工作線程有時會被阻塞,所以一段時間後池中沒有線程可用。
在我的公司,我們使用的是網狀偵聽連接形式GPS跟蹤設備原來的問題。跟蹤器通過GPRS進行通信。
我們經歷了netty 3.2.4-final的非常奇怪的行爲。
經過一段時間(我不能確切地說出多少,但接近一天),我們沒有收到跟蹤器發送的任何消息。這意味着我們實現SimpleCahnnelUpstreamHandler的messageReceived方法將不會被調用!但是,如果我使用tcpdump捕獲所有數據包,則可以看到所有消息進入!
這是一個已知問題,已經在更高版本的netty中修復了嗎?
我們的渠道管道是這樣的:
...
final TcpListenerChannelHandler tcpChannelHandler;
@Inject
public TcpListenerPipeline(TcpListenerChannelHandler tcpChannelHandler) {
this.tcpChannelHandler = tcpChannelHandler;
}
@Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline p = Channels.pipeline();
p.addLast("frameDecoder", new DelimiterBasedFrameDecoder(2048, Delimiters.lineDelimiter()));
p.addLast("encoder", new ByteArrayWrapperEncoder());
p.addLast("handler", tcpChannelHandler);
return p;
}
...
我們實例監聽方式如下:
public void startListen() {
ChannelFactory channelFactory = new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool(),20);
bootstrap = new ServerBootstrap(channelFactory);
bootstrap.setPipelineFactory(pipeline);
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.keepAlive", true);
lazyLogger.getLogger().info("Binding Tcp listener to 0.0.0.0 on port '{}'", listenPort);
serverChannel = bootstrap.bind(new InetSocketAddress("0.0.0.0", listenPort));
}
沒有任何人有什麼線索可能是錯的?或者我們應該手動斷開所有的頻道嗎?
編輯:
我對這個問題
當沒有消息被處理一些更多的信息,它也會發生channelConnected不叫成功的遠程連接。我遠程調試的問題,同時發現:
- 在NioServerSocketPipelineSink.java線#246 registerAcceptedChannel(acceptedSocket,currentThread);發生
- 軟件執行一直到 DefaultChannelPipeline行#781有不同的事件,但我的TcpListenerChannelHandler從來沒有在他的上下文中。
最奇怪的是,有時netty會注意到某個通道已連接,有時卻不會。
EDIT2:
TcpListenerCahnnelHandler是一個簡單的實現SimpleChannelUpstreamHandler
從它亮點:
public class TcpListenerChannelHandler extends SimpleChannelUpstreamHandler {
...
@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
super.channelConnected(ctx, e);
_logger.info("{} device connected from: {}", deviceProtocol.getName(), ctx.getChannel().getRemoteAddress());
deviceConnectionRegistry.channelConnected(ctx.getChannel());
}
@Override
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
super.channelDisconnected(ctx, e);
_logger.info("{} device from endpoint '{}' disconnected.", deviceProtocol.getName(), ctx.getChannel().getRemoteAddress());
deviceConnectionRegistry.channelDisconnected(ctx.getChannel());
}
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent messageEvent) throws Exception {
super.messageReceived(ctx, messageEvent);
...
NOTE: here we process the meassage, I do not think it can cause any problem
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
if(_logger.isWarnEnabled())
_logger.warn(deviceProtocol.getName()+ " device"
+e.getChannel().getRemoteAddress()+" channel", e.getCause());
if (!(e.getCause() instanceof ConnectException))
e.getChannel().close();
}
在我已經升級到3.3.1決賽的同時。如果問題再次發生,我有一些想法在哪裏繼續調試。
編輯3:
我已經升級到3.3.1最終,兩天後同樣的問題又發作了。
我不知道它是否相關,但我們在同一個物理接口上有更多的IP地址。我們是否應該嘗試只聽一個界面?有更多的eth接口有任何已知的問題嗎?
但同樣:tcpdump識別跟蹤器的消息,但netty不會在我的自定義處理程序中調用messageReceived。
EDIT 4:
我進一步調試的代碼。問題發生在NioWorker.java 在第131行(boolean offered = registerTaskQueue.offer(registerTask);)運行正常,但是這個任務永遠不會被處理。這意味着748行的RegisterTask.run()永遠不會被調用。
是否可以包含您的自定義處理程序? – 2012-04-12 12:03:39
我已經包含了TcpListenerChannelHandler的相關部分,這是唯一的自定義處理程序,這有助於嗎? – Szobi 2012-04-13 15:43:00