需求:
有一个命令序列,包含三个命令
每个命令,对应的服务端都可能会返回一个字符串。
现在的需求是:
step1.发送命令1,如果服务端没返回结果,重新发送,如果返回了,则执行step2
step2.发送命令2,如果服务端没返回结果,重新发送,如果返回了,则执行step3
step3.发送命令3,如果服务端没返回结果,重新发送,如果返回了,则执行step1
针对这个需求,我之前也在问答模块里提过问,但是没人回答,请看下面的:
http://www.iteye.com/problems/86196
现在通信框架是基于Mina2的,Mina其实提供了同步通信操作
session.getConfig().setUseReadOperation(true);
但是实际用起来,却发现无法达到同步效果。网上也有类似的疑问,具体表现为:如果发送一条命令后,在给定的超时时间内,无法获取服务端相应,则后续的通讯将阻塞。简单的说就是如果通讯一旦产生超时,则无法恢复通讯。
我搜了一下网上的资源,也有人提到过这个问题:
http://bochengwen.iteye.com/blog/982062
进一步搜索发现在Mina网站上,还有外国人提过这个问题,但是一直都是Open状态。
https://issues.apache.org/jira/browse/DIRMINA-777?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel
引用
- Status: Open Open
- Resolution: Unresolved
- Fix Version/s: 2.0.5
我当时也参与了评论,但是用的是中文文字,后来管理员直接把我的评论屏蔽了,而且还说:
Emmanuel Lecharny 写道
Emmanuel Lecharny added a comment - 19/Jul/12 07:26
Please, *do not* add comments in a foreign language... (even if those are related to the problem, google translate is not that good in chinese...)
晕死啊,老外就是老外。
看样子是准备2.0.5这个版本中fixed掉。对于这个bug,网上有网友提出了临时解决方案
((AbstractIoSession) session).offerReadFuture(null);// 针对同步实现的bug
其实这样做并不能达到效果,具体原因我不想多说。我目前的解决方法是
String request = "XXXX";
/**发送数据到服务端**/
session.write(IoBuffer.wrap(request.getBytes()));
/**
* 获取Client.class的锁定,进入wait set,等待
* 直到在Decoder中获取到了服务端响应的数据,notify,或者超时
*/
synchronized(Client.class){
try {
Client.class.wait(3000L);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
/**下面的代码就是接收到数据后或者wait超时后执行的**/
codes...
在Decoder类中
@Override
public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)
throws Exception {
synchronized (Client.class) {
Client.class.notifyAll();//唤醒
}
othercode...
}
具体的notify的时机,应该根据需求而定的,例如我只要监听服务端返回数据就notiry的话,直接写在这里就行了,如果说还要判断数据是正确的才能发送下一条命令,那么显然放在这里notify是不合适的。
附:串口通讯程序
package comm;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import javax.comm.CommPortIdentifier;
import javax.comm.SerialPort;
import javax.comm.SerialPortEvent;
import javax.comm.SerialPortEventListener;
/**
* java串口通讯
*
* @author administrator
* @since comm 1.0.0
* @created 2012-8-2
*/
public class Comm {
private SerialPort sPort;
private OutputStream os ;
private Map<String,List<String>> commands;
private Recieved rec;
public Comm(){
commands = new ConcurrentHashMap<String, List<String>>();
List<String> command1 = new ArrayList<String>();
//初始化commands...
}
public boolean init(){
try{
CommPortIdentifier portId = CommPortIdentifier.getPortIdentifier("COM3");
sPort = (SerialPort) portId.open("TPS", 1000);
sPort.setOutputBufferSize(8);
sPort.setSerialPortParams(9600,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);
rec = new Recieved(sPort);
sPort.addEventListener(rec);
sPort.notifyOnDataAvailable(true);
sPort.enableReceiveTimeout(1000);
os = sPort.getOutputStream();
}catch(Exception e){
return false;
}
return true;
}
public void start(){
Timer t = new Timer();
t.schedule(new TimerTask(){
@Override
public void run() {
final Iterator<Entry<String,List<String>>> it = commands.entrySet().iterator();
while(it.hasNext()){
Entry<String,List<String>> e = it.next();
for(String s:e.getValue()){
System.out.println(e.getKey()+","+s);
try {
os.write(s.getBytes());
} catch (IOException e1) {
e1.printStackTrace();
}
synchronized (Comm.class) {
try {
Comm.class.wait(15000);
} catch (InterruptedException e1) {
Thread.currentThread().interrupt();
}
}
}
}
}
}, 1000,2000);
}
public static void main(String[] args) {
Comm c = new Comm();
c.init();
c.start();
}
}
class Recieved implements SerialPortEventListener {
private InputStream is;
private SerialPort sPort;
private StringBuffer msg = new StringBuffer();
public Recieved(SerialPort sPort){
this.sPort = sPort;
}
@Override
public void serialEvent(SerialPortEvent e) {
try {
is = sPort.getInputStream();
} catch (IOException e2) {
e2.printStackTrace();
}
if (e.getEventType()==SerialPortEvent.DATA_AVAILABLE) {
try {
while(is.available() > 0){
msg.append((char)is.read());
}
} catch (IOException e1) {
e1.printStackTrace();
}
if(msg.toString().startsWith("%R1P")&&msg.toString().endsWith("\r\n")){
System.out.println("recieved:"+msg);
msg = new StringBuffer("");
synchronized (Comm.class){
Comm.class.notifyAll();
}
}
}
}
}
分享到:
相关推荐
自己写的demo,完成了mina的双向通信功能,比较简单的一个demo,扩展性强
完整的mina双向通信demo,实现了客户端与服务端之间相互发送消息。目前只支持发送输入的字符串。demo中有详细的注释,可以直接运行。运行环境(myeclipse+tomcat7.0)
基于mina开发的移动开发段,用于初学者,实现服务器和客户端的通信.
本源码是《NIO框架入门(三):iOS与MINA2、Netty4的跨平台UDP双向通信实战》一文的服务端实现(MINA2版),详见:http://www.52im.net/thread-378-1-1.html
这是一个有关Mina在Java通信中运用的简单的入门实例,MIna自带一种触发机制,无需再开线程等待收发数据。这个实例中有客户端和服务端,与软件TCPUDPDbg进行文字通话测试。用的时候注意添加Mina包,此实例中用到的是...
本代码包含mina服务端,同步客户端-即短连接方式,异步客户端-即长连接方式。
mina简单通信需要的包,博客地址http://blog.csdn.net/guozeming122/article/details/18552483
本源码是《NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示》一文的MINA2服务端源码实现,详见:http://www.52im.net/thread-373-1-1.html
Mina通信框架应用示例,学会运用Mina 框架
通过Mina与Socket实现通信,其包含客户端与服务端的实现代码
基于Mina架构开发的可配置的Socket Server,后台采用MySql数据库,可以独立app部署或Tomcat Servlet部署,包括Socket Server全部实现代码,后台MySql数据备份文件,Java测试代码,android端测试代码和iOS端测试代码...
MINA网络通信框架.pdf
本源码是《NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示》一文的Java客户端源码实现,详见:http://www.52im.net/thread-373-1-1.html
工作中的一个小项目,分享给大家参考,望大家不吝批评指教,本人常年从事JAVA软件开发,有丰富的MINA通信软件开发经验,现在已经有成熟的底层框架(结合了反射、DynaBean、Spring等多种技术),可以实现程序自动对...
Mina采取异步I/O和事件驱动机制,有很高的效率和性能。Mina是用于开发高性能和高可用性的网络应用程序的基础框架
本库是对我在项目中使用的Mina和长连接的一个封装,亲测有效,在网络良好的情况下,几乎能够保证100%的连接和通讯;
基于mina的短连接组件(内含binary与source包),关于本组件的说明见配套的文章:https://blog.csdn.net/smartcore/article/details/80084634
Mina自定义协议通信的示例
实现了Mina框架简单的换行符编解码的服务器客户端通信,简单自定义协议(报头式)的即时通讯
Apache Mina Server 是一个网络通信应用框架 基于 TCP/IP、UDP/IP协议栈的通信框架 支持串口和虚拟机内部的管道等传输方式 Mina 可以帮助我们快速开发高性能、高扩展性的网络通信应用 Mina 提供了事件驱动、异步操作...