`
cuisuqiang
  • 浏览: 3956298 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
3feb66c0-2fb6-35ff-968a-5f5ec10ada43
Java研发技术指南
浏览量:3666816
社区版块
存档分类
最新评论

SNMP4J包 TCP-消息发送时的一个BUG

阅读更多

在实际使用中,发现这样的一个问题,客户端(工业级交换机)和本地服务端的连接总是中断,当然不是超时自动清理的。

这个中断,有时可以建立上并能正常使用,有时连接上了却不正常使用这个连接。后台日志打印,明明连接已经存在却一直报错说是通道已经关闭。

 

经过多次测试和断点跟踪,发现交换机在一定时间不实用的话就认定连接中断,马上进行连接重建,而此时如果服务端正在给客户端发送消息,就会在一定几率上造成连接建立却无法继续使用的情况

发生这种情况时,会一直在某个地方报错连接通道已经关闭,DefaultTcpTransportMapping 内部类 ServerThread 的 processPending 方法:

private void processPending() {
  synchronized (pending) {
	for (int i=0; i<pending.size(); i++) {
	  SocketEntry entry = (SocketEntry)pending.getFirst();
	  try {
		// Register the channel with the selector, indicating
		// interest in connection completion and attaching the
		// target object so that we can get the target back
		// after the key is added to the selector's
		// selected-key set
		if (entry.getSocket().isConnected()) {
		  entry.getSocket().getChannel().register(selector,
			  SelectionKey.OP_WRITE);
		}
		else {
		  entry.getSocket().getChannel().register(selector, SelectionKey.OP_CONNECT);
		}
	  }
	  catch (IOException iox) {
		logger.error(iox);
		// Something went wrong, so close the channel and
		// record the failure
		try {
		  entry.getSocket().getChannel().close();
		  TransportStateEvent e =
			  new TransportStateEvent(DefaultTcpTransportMapping.this,
									  entry.getPeerAddress(),
									  TransportStateEvent.STATE_CLOSED,
									  iox);
		  fireConnectionStateChanged(e);
		}
		catch (IOException ex) {
		  logger.error(ex);
		}
		lastError = iox;
		if (SNMP4JSettings.isFowardRuntimeExceptions()) {
		  throw new RuntimeException(iox);
		}
	  }
	}
  }
}

 

可以看到他发生异常后,就会把通道的连接关闭,然后进行一次状态改变事件的通知。

可是在交换机重建连接后应该是马上可以使用的,为什么会报错通道不可用呢?

 

我开始认为是某些异常处理时把通道给关闭了,但是经过跟踪和测试应该不是这个问题。

看到他是在操作 pending 这个对象,而且是线程安全的,所以我跟踪了下关于这个对象的操作,他的定义是这样的:

private LinkedList pending = new LinkedList();

 

是个集合,往集合里面增加东西是在消息发送时操作的:

public void sendMessage(Address address, byte[] message)  throws java.io.IOException  {
  Socket s = null;
  SocketEntry entry = (SocketEntry) sockets.get(address);
  if (logger.isDebugEnabled()) {
	logger.debug("Looking up connection for destination '"+address+ "' returned: "+entry);
	logger.debug(sockets.toString());
  }
  if (entry != null) {
	s = entry.getSocket();
  }
  if ((s == null) || (s.isClosed()) || (!s.isConnected())) {
	if (logger.isDebugEnabled()) {
	  logger.debug("Socket for address '"+address+  "' is closed, opening it...");
	}
	pending.remove(entry);
	SocketChannel sc = null;
	try {
		// Open the channel, set it to non-blocking, initiate connect
		sc = SocketChannel.open();
		sc.configureBlocking(false);
		sc.connect(new InetSocketAddress(((TcpAddress)address).getInetAddress(), ((TcpAddress)address).getPort()));
		s = sc.socket();
		entry = new SocketEntry((TcpAddress)address, s);
		entry.addMessage(message);
		sockets.put(address, entry);
		synchronized (pending) {
		  pending.add(entry);
		}
		selector.wakeup();
		logger.debug("Trying to connect to "+address);
	}
	catch (IOException iox) {
	  logger.error(iox);
	  throw iox;
	}
  }
  else {
	entry.addMessage(message);
	synchronized (pending) {
	  pending.add(entry);
	}
	selector.wakeup();
  }
}

 

跟踪断点会发现,如果客户端不可用的情况下你发送消息,他会进if ((s == null) || (s.isClosed()) || (!s.isConnected())) 的判断区域,那么这个区域的代码执行的操作却是建立针对这个地址建立一个客户端连接然后发送数据。

这显然不对,而且因为他建立连接时正好处于交换机的重启或连接重建时,不会报错,所以就会造成这个消息被当成自己是客户端对方是服务端给处理了。

而执行 processPending 方法时,正好在 entry.getSocket().getChannel().close(); 之前交换机的客户端连接过来了,连接刚刚建立这里就执行了entry.getSocket().getChannel().close();  你再使用这个连接发送消息,就会一直提示通道已经关闭!

 

我的建议是,这里不应该认定没有连接存在就把这个消息当客户端消息给发送,应该是如果不是服务端再进行上面说的判断区域。

而且DefaultTcpTransportMapping 类中有是否是服务端的属性:

private boolean serverEnabled = false;

 

如果你是服务端,那么这个属性就是 TRUE 。

 

所以消息发送时应该是这样判断:

// TODO 如果本地不是服务端,则创建连接再发送
if (!serverEnabled) {

 

如果你的消息都是当成服务端去发送了,那么这个连接一旦建立成功,且此时程序还在处理中,那么消息照样是发送成功的!

 

请您到ITEYE网站看原创,谢谢!

http://cuisuqiang.iteye.com/ ! 

自建博客地址:http://www.javacui.com/ ,内容与ITEYE同步!

2
2
分享到:
评论

相关推荐

    snmp4j最新开发包

    SNMP4J是一个Java实现的简单网络管理协议(SNMP...以上是SNMP4J 2.3.1开发包的主要知识点,这个版本的更新可能包含性能改进、bug修复和对新SNMP规范的支持,为开发者提供了更可靠的工具来处理SNMP相关的网络管理任务。

    C语言实现的snmp服务源码

    总的来说,C语言实现的SNMP服务源码是一个涉及网络协议、加密安全、系统编程等多个领域的复杂项目。理解和分析这样的源码,不仅有助于深入学习SNMP协议,也有助于提升C语言编程和网络管理的能力。

    x-SCAN -V3.3-CN.

    A:端口扫描中的“SYN”方式在NT4或XP+SP2系统下无法使用,在windows 2000等系统下使用时必须拥有管理员权限,否则将自动改用“TCP”方式进行端口扫描。 Q:新版本是否兼容2.3版本的插件? A:X-Scan 3.0以上...

    强大的扫描工具x-scan

    A:检测每个主机都会单独起一个Checkhost.exe进程,检测完毕会自动退出。并发主机数量可以通过 图形界面的设置窗口设定,命令行程序通过“-t”参数设定。 Q:扫描过程中机器突然蓝屏重启是什么原因? A:扫描...

    X-Scan v3.1

    “顺序执行针对服务的破坏性脚本” - 如果一个脚本正在尝试D.O.S某个服务,另一个脚本同时在获取该服务信息,或同时有其他脚本尝试溢出该服务,将导致扫描结果不正确。但如果脚本间不需要互相等待,将会节省扫描...

    X-Scan

    - 打开脚本选择窗口,通过风险级别、检测手段、漏洞类型等分类方式定制脚本列表 “脚本运行超时(秒)” - 设置一个脚本可运行的最长时间,超时后将被强行终止 “网络读取超时(秒)” - 设置TCP连接每次...

    haproxy-1.5下载

    haproxy-1.5-dev19这个文件名可能表示这是一个开发版本,虽然可能包含一些新特性或修复的bug,但在生产环境中使用时,通常建议选择正式的稳定版本以确保最佳的稳定性和安全性。不过,对于开发者来说,测试这些开发...

    libnet.dll libnet.lib编译后的库

    8. **版本控制**:libnet1.1.2表示一个特定的版本,可能包含前一版本的改进、新功能或bug修复。 9. **软件开发**:使用libnet库的开发者需要了解如何在自己的代码中正确引入和使用这些库文件,包括链接选项、头文件...

    基于Mini2440平台的RT-ThreadRTOS开发手册.pdf

    在实际开发过程中,开发者可能会遇到各种bug,因此,如何定位和修复RTOS中的bug也应是手册中的一个重点内容。此外,文档可能还会介绍一些高级特性,例如RT-Thread的多线程和时间管理功能,以及如何与硬件如ARM处理器...

    ICS delphixe10源码版

    .\Samples\delphi\OtherDemos Delphi Win32/Win64 DNS, Ping, SNMP, Syslog sample applications (all Delphi versions) .\Samples\delphi\PlatformDemos Delphi FireMonkey and cross-platform samples (Delphi XE2...

    J2EE程序员需掌握的技术

    - Log4j,Jakarta Commons Logging:日志记录工具。 15. **缓存框架**: - OSCache,JBoss Cache,Ehcache:提高性能的缓存解决方案。 16. **工作流**: - jBPM:工作流管理系统。 17. **Portal**: - JBoss ...

    基本服务端口很详细的哦

    - **用途**:主要用于访问USENET(一个全球性的分布式对话系统)中的新闻组,允许用户发布、检索和搜索新闻文章。 #### 2. 135 - Location Service (DCOM/DCERPC Endpoint Mapper) - **定义**:此端口主要用于...

    Radware AppDirector负载均衡器指导书2.11v1.0

    - **VIP (Virtual IP)**:虚拟IP地址,客户端访问的入口,用于指向Farm中的一个或多个真实服务器。 - **Server**:真实服务器,处理客户端请求的具体机器。 - **Policy**:负载均衡策略,包括L4(第四层)和L7(第七...

    快速上手OpenVAS系统漏扫工具,实战win10物理机漏扫,更新OpenVAS漏洞库,报错解决

    OpenVAS(Open Vulnerability Assessment System)是一个开源的安全漏洞扫描工具,可以用来发现系统或网络中存在的安全漏洞。它支持多种协议,包括但不限于SNMP、FTP、HTTP、HTTPS、NFS、SMB等,用于检测远程主机或...

    php.ini-development

    4. Current working directory (except CLI) ; 5. The web server's directory (for SAPI modules), or directory of PHP ; (otherwise in Windows) ; 6. The directory from the --with-config-file-path compile ...

    Citrix负载均衡设备配置手册10.1

    设备初始化配置规范是手册的另一个重点,包括了前期准备工作、初始化设备连接、安装LICENSE、操作系统升/降级以及基本选项配置。例如,在前期准备工作里,提到了连接MPX管理接口、设备上架加电、两台MPX之间的网络...

Global site tag (gtag.js) - Google Analytics