安卓Websocket客户端超时问题

7

谢谢阅读!

背景: 我正在为一个需要与基于 WebSockets 的服务器不断交换消息的应用程序开发Android客户端。

实现:对于客户端,我使用weberknecht's Android WebSocket客户端库,而服务器则基于Tornado

问题: 目前,我通过生成一个AsyncTaskonCreate中调用initWebSocketClient。但是,我一直收到客户端超时异常。

Android客户端:


private void initWebSocketClient() {
        Log.e(TAG, "initWebSocketClient");
        try {
            URI url = new URI("ws://192.168.207.84:8080/");
            WebSocket websocket = new WebSocketConnection(url);

            // Register Event Handlers
            websocket.setEventHandler(new WebSocketEventHandler() {
                    public void onOpen()
                    {
                            Log.e(TAG, "--open");
                    }

                    public void onMessage(WebSocketMessage message)
                    {
                            Log.e(TAG, "--received message: " + message.getText());
                    }

                    public void onClose()
                    {
                            Log.e(TAG, "--close"); 
                    }
            });

            // Establish WebSocket Connection
            websocket.connect();

            // Send UTF-8 Text
            websocket.send("hello world");

            // Close WebSocket Connection
            websocket.close();
        }
        catch (WebSocketException wse) {
                wse.printStackTrace();
        }
        catch (URISyntaxException use) {
                use.printStackTrace();
        }
    }

Tornado服务器:


#!/usr/bin/env python

import tornado.ioloop
import tornado.web
import tornado.websocket

class EchoWebSocketHandler(tornado.websocket.WebSocketHandler):
    def open(self):
        print "WebSocket opened"

    def on_message(self, message):
        self.write_message(u"You said: " + message)

    def on_close(self):
        print "WebSocket closed"

application = tornado.web.Application([
    (r"/", EchoWebSocketHandler),
])

if __name__ == "__main__":
    application.listen(8080)
    tornado.ioloop.IOLoop.instance().start()

客户端超时异常:

01-31 19:28:01.367: W/System.err(5668): de.roderick.weberknecht.WebSocketException: error while creating socket to ws://192.168.207.84:8080/
01-31 19:28:01.386: W/System.err(5668):     at de.roderick.weberknecht.WebSocketConnection.createSocket(WebSocketConnection.java:244)
01-31 19:28:01.386: W/System.err(5668):     at de.roderick.weberknecht.WebSocketConnection.connect(WebSocketConnection.java:83)
01-31 19:28:01.386: W/System.err(5668):     at com.sagar.websockclient.MainActivity.initWebSocketClient(MainActivity.java:55)
01-31 19:28:01.390: W/System.err(5668):     at com.sagar.websockclient.MainActivity.access$0(MainActivity.java:30)
01-31 19:28:01.390: W/System.err(5668):     at com.sagar.websockclient.MainActivity$WebSocketTask.doInBackground(MainActivity.java:75)
01-31 19:28:01.390: W/System.err(5668):     at com.sagar.websockclient.MainActivity$WebSocketTask.doInBackground(MainActivity.java:1)
01-31 19:28:01.390: W/System.err(5668):     at android.os.AsyncTask$2.call(AsyncTask.java:264)
01-31 19:28:01.390: W/System.err(5668):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
01-31 19:28:01.390: W/System.err(5668):     at java.util.concurrent.FutureTask.run(FutureTask.java:137)
01-31 19:28:01.390: W/System.err(5668):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
01-31 19:28:01.390: W/System.err(5668):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
01-31 19:28:01.390: W/System.err(5668):     at java.lang.Thread.run(Thread.java:856)
01-31 19:28:01.390: W/System.err(5668): Caused by: java.net.ConnectException: failed to connect to /192.168.207.84 (port 8080): connect failed: ETIMEDOUT (Connection timed out)
01-31 19:28:01.390: W/System.err(5668):     at libcore.io.IoBridge.connect(IoBridge.java:114)
01-31 19:28:01.394: W/System.err(5668):     at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:192)
01-31 19:28:01.394: W/System.err(5668):     at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
01-31 19:28:01.394: W/System.err(5668):     at java.net.Socket.startupSocket(Socket.java:566)
01-31 19:28:01.394: W/System.err(5668):     at java.net.Socket.tryAllAddresses(Socket.java:127)
01-31 19:28:01.394: W/System.err(5668):     at java.net.Socket.(Socket.java:177)
01-31 19:28:01.394: W/System.err(5668):     at java.net.Socket.(Socket.java:149)
01-31 19:28:01.394: W/System.err(5668):     at de.roderick.weberknecht.WebSocketConnection.createSocket(WebSocketConnection.java:238)
01-31 19:28:01.394: W/System.err(5668):     ... 11 more
01-31 19:28:01.394: W/System.err(5668): Caused by: libcore.io.ErrnoException: connect failed: ETIMEDOUT (Connection timed out)
01-31 19:28:01.398: W/System.err(5668):     at libcore.io.Posix.connect(Native Method)
01-31 19:28:01.398: W/System.err(5668):     at libcore.io.BlockGuardOs.connect(BlockGuardOs.java:85)
01-31 19:28:01.398: W/System.err(5668):     at libcore.io.IoBridge.connectErrno(IoBridge.java:127)
01-31 19:28:01.398: W/System.err(5668):     at libcore.io.IoBridge.connect(IoBridge.java:112)
01-31 19:28:01.398: W/System.err(5668):     ... 18 more

我需要帮助,内容与编程有关。

更新:添加AutoBahn(Android的WebSocket客户端库)实现细节:

AutoBahn客户端


private void connect2() {
        mConnection = new WebSocketConnection();
        final String wsuri = "ws://192.168.0.137:8888/";
        String TAG = "ArticlesListActivity"; 

        try {
            mConnection.connect(wsuri, new WebSocketHandler() {
               @Override
               public void onOpen() {
                 Log.e(TAG, "Connected to: " + wsuri);
               }

               @Override
               public void onTextMessage(String payload) {
                  Log.e(TAG, "Message recieved = " + payload);
               }

               @Override
               public void onClose(int code, String reason) {
                  Log.e(TAG, "Connection Lost.");
               }
            });
         } catch (WebSocketException e) {

            Log.d(TAG, e.toString());
         }      
    }

使用这个库,我能够连接到服务器,但是连接很快就会丢失。(请参考下面的“AutoBahn客户端日志”。切换回weberknecht则完全正常。我没有在任何地方显式调用mConnection.disconnect(),所以我不知道连接是如何被终止的。) AutoBahn客户端日志

02-27 14:27:36.605: D/de.tavendo.autobahn.WebSocketConnection(27701): created
02-27 14:27:36.656: D/dalvikvm(27701): GC_FOR_ALLOC freed 164K, 4% free 9247K/9543K, paused 17ms
02-27 14:27:36.671: D/dalvikvm(27701): GC_FOR_ALLOC freed 7K, 4% free 9368K/9735K, paused 14ms
02-27 14:27:36.671: D/de.tavendo.autobahn.WebSocketReader(27701): created
02-27 14:27:36.675: D/de.tavendo.autobahn.WebSocketConnection(27701): WS reader created and started
02-27 14:27:36.675: D/de.tavendo.autobahn.WebSocketReader(27701): running
02-27 14:27:36.675: D/de.tavendo.autobahn.WebSocketWriter(27701): created
02-27 14:27:36.675: D/de.tavendo.autobahn.WebSocketConnection(27701): WS writer created and started
02-27 14:27:36.769: D/de.tavendo.autobahn.WebSocketReader(27701): run() : ConnectionLost
02-27 14:27:36.773: D/de.tavendo.autobahn.WebSocketReader(27701): ended
02-27 14:27:36.777: D/de.tavendo.autobahn.WebSocketConnection(27701): opening handshake received
02-27 14:27:36.777: E/ArticlesListActivity(27701): Connected to: ws://192.168.0.137:8888/
02-27 14:27:36.781: D/de.tavendo.autobahn.WebSocketConnection(27701): fail connection [code = 3, reason = WebSockets connection lost
02-27 14:27:36.784: D/de.tavendo.autobahn.WebSocketReader(27701): quit
02-27 14:27:36.788: D/de.tavendo.autobahn.WebSocketWriter(27701): ended
02-27 14:27:36.792: E/ArticlesListActivity(27701): Connection Lost.
02-27 14:27:36.792: D/de.tavendo.autobahn.WebSocketConnection(27701): worker threads stopped
2个回答

5
据我所知,Weberknecht仅支持Hybi-10协议,而不支持最终的RFC6455规范。更为问题的是,它在主线程(UI线程)上进行网络操作。这通常是一个坏主意,并且将在Android>2上失败。
对于Android原生应用程序,有Autobahn WebSockets for Android可用。

https://github.com/oberstet/AutobahnAndroid

它支持最终的RFC6455,与UI和服务应用程序集成良好,提供WebSockets上的RPC和PubSub等功能。请在GitHub上查看项目README。
免责声明:我是Autobahn的作者。

代码采用Apache 2.0许可证,是开源的。关于AsyncTask,最新的代码不需要它了,因为不仅套接字的读写在后台线程中完成,而且初始套接字连接也是如此。直到最近,这一点是不同的,只有读/写在后台线程中完成,但初始套接字连接不是,这会导致在最近的Android上出现“UI上的网络”线程问题。 - oberstet
我明白了,感谢您提供的详细信息。它支持Tornado Websockets 2.2吗?因为就在今天,我发现weberkneckt只支持最高到2.1。 - Sagar Hatekar
1
Autobahn for Android支持WebSockets协议草案版本Hybi-10直到最终的RFC6455。我不知道Tornado WS 2.2实现了什么。 - oberstet
我尝试使用AutoBahn“广播客户端”库。请参见上面的“更新”。但我无法连接到服务器。你能帮我吗? - Sagar Hatekar
1
对我来说没问题:Tornado 2.2 + 您上面的代码 + Autobahn Android 的 Echo 客户端演示。可能 Tornado 2.1 WS 实现可能太旧了..尝试使用2.2.. - oberstet
显示剩余10条评论

5

以下是我开始解决问题的步骤:

  1. Are you attempting to do this on your phone (device) or the emulator? If you're attempting to do this on your phone and you're connected via 3G, it is not going to happen. In this scenario, you're attempting to connect to an internal IP address from the WAN which doesn't work.

  2. Again assuming you're doing this on a device, if you're connected via Wifi then it's another story. Make sure the server can be reached at 192.168.207.84:8080. A quick way to test connectivity (from your PC):

    telnet 192.168.207.84 8080
    

    If it times out, you know your server isn't responding. This of course assumes your PC is on the same subnet as your Wifi network.

  3. If you're attempting to do this from your emulator, follow the steps in [2] to make sure the server is reachable and also ensure your emulator is in (IP) bridged mode.

总结一下,超时通常发生的主要原因是由于服务器不可用(即连接不可用)。您没有提及网络的详细情况,因此我根据您尝试连接的IP地址(192.168.207.84)做了一些假设。

太棒了!感谢@Marvin提供详细的解释,这完全帮助我解决了问题。我一直在使用设备,但我的服务器位于内部IP上。所以,现在我将服务器和设备都连接到同一个WiFi上,并成功连接了服务器! - Sagar Hatekar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接