【问题标题】:.read() throws intermittent SocketTimeoutException even though data should be there.read() 会抛出间歇性的 SocketTimeoutException,即使数据应该在那里
【发布时间】:2011-08-03 17:29:24
【问题描述】:

我正在为 Android 开发一个 Web 服务器,尽管我花了几天时间试图修复它,但我对这个特定的错误束手无策。我正在尝试从浏览器读取请求,并且代码大部分时间都可以正常工作,但是有 5% 的请求失败并且它会抛出随机 SocketTimeoutExceptions,甚至没有从 Socket 读取单个字符。

我已经用不同的浏览器对此进行了测试,并且所有浏览器都会发生这种情况,所以问题很可能出在我身上。以下是相关代码,尽可能精简:

public class ServerThread extends Thread {

private ServerSocket ss = null;
private boolean isRunning;

private ExecutorService threadPool = new ThreadPoolExecutor(2, 12,
          60L, TimeUnit.SECONDS,
          new SynchronousQueue<Runnable>(),
          Executors.defaultThreadFactory(), 
          new ThreadPoolExecutor.CallerRunsPolicy());

public ServerThread() {
}

public synchronized void run() {
    ss = new ServerSocket(8080, 1);
    isRunning = true;

    while (isRunning) {
        Socket clientSocket = null;

        try {
            if (ss != null) {
                clientSocket = ss.accept();
                if (isRunning) {
                    this.threadPool.execute(new HTTPSession(clientSocket));
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
}

还有:

public class HTTPSession implements Runnable {

private Socket mSocket = null;

public HTTPSession (Socket s) {
    mSocket = s;
}


public void run() {

    InputStream ips = null;

    try {
        mSocket.setSoTimeout(15000);
        ips = mSocket.getInputStream();
        ips.read();
    }
    catch (Exception e) {
        e.printStackTrace();
        Log.v("HTTPSession", "Socket connected: " + mSocket.isConnected() + ", Socket closed: " + mSocket.isClosed() + ", InputShutdown: " + mSocket.isInputShutdown());
    }
    finally {
            try { ips.close(); } catch (IOException ioe) {  }
            try { mSocket.close(); } catch (IOException ioe) {  }
    }

}
}

所以 ServerThread 接受连接,HTTPSession 尝试从 Socket 读取,有时它会在 15 秒后抛出 SocketTimeoutException。

在这种情况下,catch 中的 Log 语句的输出是: 套接字已连接:true,套接字已关闭:false,InputShutDown:false

什么给了?当然 15 秒的等待时间就足够了,主流网络浏览器似乎不太可能不发送任何数据,那我为什么看不到呢?

我将不胜感激有关此问题的任何意见。

【问题讨论】:

    标签: java android multithreading sockets


    【解决方案1】:

    SocketTimeoutException 只意味着一件事:在超时时间内没有可用的数据。所以是的,也许你的超时太短了,是的,浏览器没有在超时期限内发送它,或者至少它没有在超时期限内到达服务器的套接字接收缓冲区。

    我会说 15 秒对于服务器端超时来说有点激进。 30 到几分钟会更合适。

    【讨论】:

    • 谢谢!也许我应该提到,完整的代码实际上将套接字绑定到 wifi IP,因此它是一个相对高带宽/低延迟的环境。我尝试使用更长的超时时间,但发现我得到了相同数量的异常。短暂超时的另一个原因是我不希望用户盯着空白屏幕两分钟,因为在 15 秒后发送成功请求的可能性很小。
    【解决方案2】:

    我看不出这段代码会以这种方式失败的任何原因,除非就像你说的那样,浏览器没有发送任何东西。您可以将 ips.read(); 更改为 System.out.println(ips.read()); 以确保这一点。如果您在标准输出上看到一个字节,那么浏览器确实发送了一些东西。我的猜测是,在您的完整代码中,您没有正确识别请求的结束并继续等待更多数据。 15 秒后,您将超时。但这只是一个猜测。如果您发布一些演示问题的代码,有人可能会给您一个明确的答案。

    【讨论】:

    • 感谢您的建议。当抛出异常时,这绝对是第一次读取失败而没有读取单个字节。我开始认为这是一个特定于设备的问题。我刚才在不同的设备上运行了相同的代码,并且无法在超过 10k 的请求中引发错误。将相同的 -apk 放在 Motorola Milestone XT720 上,它会为前 50 个请求引发 5 个异常。
    • 我不知道你会如何检查类似的东西。有没有类似wireshark 的android 实用程序?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-11-28
    • 2012-06-03
    • 1970-01-01
    • 2015-01-14
    • 1970-01-01
    • 2012-05-16
    • 1970-01-01
    相关资源
    最近更新 更多