【问题标题】:Problem using org.apache.commons.net.telnet.* with android将 org.apache.commons.net.telnet.* 与 android 一起使用时出现问题
【发布时间】:2010-01-07 10:21:49
【问题描述】:

我在我的 Android 应用程序中使用 org.apache.commons.net.telnet.* 库时遇到问题,我希望有人可以帮助我。

我已经实现了一个使用 telnet 与远程服务器通信的应用程序,并且一切正常。我遇到的问题是当我调用TelnetClient.disconnect() 时,该方法没有返回。在运行测试用例时调用该方法(意味着没有 Android,仅通过 Eclipse)它会立即返回,但在 Android 上有些东西搞砸了。我的测试用例看起来像:

TelnetClient telnet = new TelnetClient();
telnet.connect(ipAddress, port); 
telnet.disconnect(); //HERE

谁能告诉我为什么会这样?

如果我从已连接的 telnet 对象中获得 InputStream,并且在调用断开连接后从 telnet 服务器发送了一些信息,则可能导致该方法返回并关闭通过调用 .connect(..) 创建的通信线程,这让我觉得某处有某种锁或锁?

Dalvik VM 或 Android 操作系统与我的 Java VM 和 XP 机器导致该行为的根本区别是什么?

感谢您的帮助,下面的堆栈跟踪!

在出现 ANR 时(由于断开连接调用无限期挂起),我有来自 TelnetClient.connect() 创建的 comm 线程的堆栈跟踪。

"Thread-15" daemon prio=6 tid=17 NATIVE | group="main" sCount=1 dsCount=0 s=N                obj=0x43812d90 self=0x1be528 | sysTid=1403 nice=-2 sched=0/0 handle=2703408 
  at org.apache.harmony.luni.platform.OSNetworkSystem.receiveStreamImpl(Native Method) 
  at org.apache.harmony.luni.platform.OSNetworkSystem.receiveStream(OSNetworkSystem.java:236) 
  at org.apache.harmony.luni.net.PlainSocketImpl.read(PlainSocketImpl.java:550) 
  at org.apache.harmony.luni.net.SocketInputStream.read(SocketInputStream.java:87) 
  at org.apache.harmony.luni.net.SocketInputStream.read(SocketInputStream.java:67) 
  at java.io.BufferedInputStream.fillbuf(BufferedInputStream.java:177) 
  at java.io.BufferedInputStream.read(BufferedInputStream.java:259) 
  at java.io.PushbackInputStream.read(PushbackInputStream.java:160) 
  at org.apache.commons.net.io.FromNetASCIIInputStream._read(FromNetASCIIInputStream.java:77) 
  at org.apache.commons.net.io.FromNetASCIIInputStream.read(FromNetASCIIInputStream.java:175) 
  at org.apache.commons.net.io.FromNetASCIIInputStream.read(FromNetASCIIInputStream.java:138) 
  at java.io.BufferedInputStream.fillbuf(BufferedInputStream.java:177) 
  at java.io.BufferedInputStream.read(BufferedInputStream.java:259) 
  at org.apache.commons.net.telnet.TelnetInputStream._read(TelnetInputStream.java:122) 
  at org.apache.commons.net.telnet.TelnetInputStream.run(TelnetInputStream.java:564) 
  at java.lang.Thread.run(Thread.java:1060)

还有来自调用.disconnect() 的线程(对于我的测试用例,它只是在主线程上):

DALVIK THREADS: "main" prio=5 tid=3 MONITOR | group="main" sCount=1 dsCount=0 s=N   obj=0x4001ab08 self=0xbc60 | sysTid=1390 nice=0 sched=0/0 handle=-1343996920 
  at java.io.BufferedInputStream.close(BufferedInputStream.java:~166) 
  at org.apache.commons.net.telnet.TelnetInputStream.close(TelnetInputStream.java:535) 
  at java.io.FilterInputStream.close(FilterInputStream.java:81) 
  at java.io.BufferedInputStream.close(BufferedInputStream.java:167) 
  at couk.mypackage.comm.TelnetClient.closeTelnet(IGSTelnetClient.java:441) 
  at couk.myoackage.comm.Translator$1.handleMessage(IGSTranslator.java:65) 
  at android.os.Handler.dispatchMessage(Handler.java:99) 
  at android.os.Looper.loop(Looper.java:123) 
  at android.app.ActivityThread.main(ActivityThread.java:4203) 
  at java.lang.reflect.Method.invokeNative(Native Method) 
  at java.lang.reflect.Method.invoke(Method.java:521) 
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791) 
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:549) 
  at dalvik.system.NativeStart.main(Native Method)

更新:

如果我明确关闭输出和输入流(javadoc 说不要这样做),而是调用disconnect(),那么我可以关闭连接,即,

out.close();
in.close();
telnet.disconnect();

我很困惑!

【问题讨论】:

  • 你能澄清一下“测试用例”和“在Android上”的区别吗?是您在模拟器/设备上运行的AndroidTestCase,还是完全独立的 JUnit?问题是出现在模拟器上还是设备上,还是两者都有?
  • 对不起,我应该更清楚。通过测试用例,我只是指在我的笔记本电脑上运行代码(而不是通过 eclipse 在任何 android 模拟器/设备上运行)。 'on android' 意味着在同一台机器上使用模拟器。没有在设备上测试过(因为我还没有!)所以只能代表模拟器(运行 1.6)。希望这能澄清上述情况
  • 没问题,您也可以编辑您的原始问题以帮助其他人澄清。 :)
  • 不是您的问题的答案,但是您是否考虑过使用 SSH 而不是 Telnet? Telnet 非常不安全(未加密),在大多数平台上已被 SSH 取代。也有可用的客户端库。
  • 问题:当您尝试断开连接时,此通信线程是否仍在尝试从输入流中读取?此外,您能否打开 adb shell 并运行挂起的版本。当它挂起时,在 shell 提示符下运行 netstat 并查看它为连接提供的状态。

标签: java android


【解决方案1】:

TelentClient extends TelnetTelnet extends SocketClient。如果您看到这些类,它将创建VT100 连接。请参阅TelnetClient.java 的以下代码。

 public TelnetClient() {
   /* TERMINAL-TYPE option (start)*/
   super ("VT100");
   /* TERMINAL-TYPE option (end)*/
   __input = null;
   __output = null;
 }

这将创建超类。请参阅Telnet.java 类中的代码。

Telnet() {
      setDefaultPort(DEFAULT_PORT);
      _doResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1];
      _willResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1];
      _options = new int[TelnetOption.MAX_OPTION_VALUE + 1];
      optionHandlers = new TelnetOptionHandler[TelnetOption.MAX_OPTION_VALUE + 1];
}

这里的DEFAULT_PORT23

现在,请参阅 SocketClient.java 中的 connect 方法。

        public void connect(InetAddress host, int port)
                throws SocketException, IOException {
            _socket_ = _socketFactory_.createSocket(host, port);
            _connectAction_();
        }

这是使用DefaultSocketFactory 创建一个新的Socket,这是一个到指定主机和端口的TCP 套接字。在connectAction 方法中,它设置了新套接字的超时时间。

现在,当我们调用disconnect 时,它首先尝试关闭套接字。

public void disconnect() throws IOException {
            _socket_.close();
            _input_.close();
            _output_.close();
            _socket_ = null;
            _input_ = null;
            _output_ = null;
            _isConnected_ = false;
        }

因为您可以直接关闭 Streams,所以似乎是套接字本身的问题。

这将是一个 TCP 套接字,我不知道 Android 如何处理 TCP。你能检查一下吗?因为此方法正在关闭 3 个私人成员。或者可能是套接字已经关闭,无法再次关闭?

希望这会有所帮助。

谢谢。

【讨论】:

    猜你喜欢
    • 2011-11-12
    • 2011-03-15
    • 2011-05-27
    • 1970-01-01
    • 2023-04-07
    • 2010-10-26
    • 2020-06-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多