2009年2月4日星期三

Telnet命令执行器----对the end of a stream的理解

现在工作中的软件框架中有一个比较严重的问题是网络命令的执行request-reponse之间没有进行很好的协调而是使用sleep, check这种糟糕的方式。
很自然联想起给Neustar做的IM软件。但telnet协议又不同于IM系统所使用的协议。前者是基于长连接,而后者是短连接。对于短链接,请求与回应很容易进行匹对。而长连接,则需要依靠同一个网络连接顺序地、依次地进行请求-回应的处理。
对于利用像telnet协议基于长连接来执行的命令,同步是其天然特性。所以对于命令的执行是没有必要进行异步处理的。(当然也可以进行异步处理,但是意义基本不大,这里异步/同步的选择应该是基于应用的不同而变化。)

先不考虑接口、抽象。直接用两个类封装逻辑。TelnetConnection利用common-net项目中的TelnetClient建立连接,获得input, output。TelnetCommond封装通过telnet协议发出的命令。
public String receiveText() {
StringBuilder sb = null;
try {
sb = new StringBuilder();
byte ch = (byte) in.read();
while (ch > 0) {
sb.append((char) ch);
ch = (byte) in.read(); // 当读到-1之后再用out发送指令之后再也不能读出response了。
// 而且读取这个-1的值时程序被阻塞!

}
} catch (IOException e) {
Log.warn(e);
}
Log.debug(sb.toString());

return sb.toString();
}


改为使用结束字符串做检查标志后就正常了。
byte ch = (byte) in.read();
while (ch > 0) {
sb.append((char) ch);
if (sb.indexOf(endFlagStr) >=0) {
break;
}
ch = (byte) in.read();
}


很奇怪,难道是apache common-net里的类TelnetInputStream实现得有问题?当inputstream读到末尾后,有新的数据进入后没有进行适当的处理?
呵呵,是我的错误!inputStream.read()返回-1说明已经读到了the end of the stream。对于有限容量的stream(比如来自文件的流)来说就是读尽了,对于未知容量的stream比如网络流,如果 read()返回-1,说明这个流可能已经被对端关闭了。总之就应该对这种情况进行处理。再读下去,也是-1。这篇文章对此有些所描述:http://publib.boulder.ibm.com/infocenter/zos/v1r9/index.jsp?topic=/com.ibm.zos.r9.rexa100/h1981605209.htm


Telnet概述及RFC: http://en.wikipedia.org/wiki/Telnet
common-net 的使用:http://www.informit.com/guides/content.aspx?g=java&seqNum=40