【问题标题】:Network I/O hangs on BlackBerry OS 5网络 I/O 在 BlackBerry OS 5 上挂起
【发布时间】:2010-07-08 19:50:25
【问题描述】:

我在黑莓 OS 5 上的网络 I/O 代码存在一些问题。

在我的 I/O 操作期间,我不断收到零星的挂起,并最终导致 TCP 超时异常。

我正在使用 5.0 网络 API 来建立每次都能完美运行的连接。

问题在于执行实际 I/O 时。我有一个后台工作线程,它为队列中的 I/O 请求提供服务。只有一个后台线程,所以所有请求都序列化到这个线程上。

完成通知是通过在请求排队时传入的委托接口完成的。

在后台工作线程上调用完成委托,但客户端可以通过invokeLater 将其重新发布到事件线程以进行 UI 更新等。

注意事项:
HttpRequest 是我自己的类,它保存有关请求的数据。
MutableData 是我自己的类,用于保存读取的数据。
BUFFER_SIZE = 2048

HttpConnection getConnectionForRequest(final HttpRequest inRequest) {
    final String url = inRequest.getURL();
    final int[] availableTransportTypes = 
        TransportInfo.getAvailableTransportTypes();
    final ConnectionFactory connectionFactory = new ConnectionFactory();
    connectionFactory.setPreferredTransportTypes(availableTransportTypes);
    connectionFactory.setConnectionMode(ConnectionFactory.ACCESS_READ);
    final ConnectionDescriptor connectionDescriptor = 
        connectionFactory.getConnection(url);
    HttpConnection connection = null;
    if (connectionDescriptor != null) {
        connection = (HttpConnection) connectionDescriptor.getConnection();
    }
    return connection;
}

public void run() {
    while (isRunning()) {
        // This blocks waiting on a request to appear in the queue.
        final HttpRequest request = waitForRequest(); 
        final HttpConnection connection = getConnectionForRequest(request);
        final MutableData data = new MutableData();
        final InputStream inputStream = connection.openInputStream();
        final byte[] readBuffer = new byte[BUFFER_SIZE];
        int chunkSize;
        // *** The following read call sporadically hangs and eventually throws
        //  a TCP timeout exception.
        while((chunkSize = inputStream.read(readBuffer, 0, BUFFER_SIZE)) != -1) {
            data.appendData(readBuffer, 0, chunkSize);
        }
        mDelegate.receivedDataForRequest(request, data);
    }
}

当它挂起时,它总是在大约 30 秒左右后最终引发 TCP 超时错误。 如果这种情况偶尔发生,我会把它归结为正常的网络拥塞,但它 频繁发生足以表明存在更深层次的问题。

编辑:

它发生在各种模拟器和我拥有的 2 个物理设备上。 我试过的模拟器是……

  • 风暴9550
  • 游览 9630
  • 加粗9000
  • 珍珠9100
  • 曲线 8530

我有一个 Curve 8530 和 Storm 9550 设备,这两种设备都会发生这种情况。

任何帮助将不胜感激。

【问题讨论】:

  • 这是模拟器还是真机?
  • 添加了设备和模拟器信息。
  • 我问的原因是因为我发现 5.0 模拟器在网络仿真方面存在相当大的问题 - 经常无缘无故地挂起连接。但是,由于您也在真实设备上看到它,所以它一定是不同的。

标签: java blackberry inputstream java-me


【解决方案1】:

您可能想尝试Available() 方法。即使您在一个后台线程上序列化数据,看起来请求是在主线程中创建的。你可能会在那里遇到一些奇怪的比赛条件。

【讨论】:

  • 我还认为我可能正在处理一种奇怪的比赛条件,但我一生都找不到。唯一的共享数据是请求队列,它在发布线程和处理线程之间正确同步。
【解决方案2】:

您能否添加一些日志记录以显示设备为每个连接选择使用的传输类型?也许这是一个传输选择 API 选择它认为可行的传输的情况,而实际上它并没有。

【讨论】:

  • 每次选择TRANSPORT_TCP_CELLULAR。
【解决方案3】:

有人建议在我的网络 I/O 线程中放置一个停止检测器,当检测到停止时,中断线程并重新启动请求。我通过在开始请求之前启动计时器来做到这一点,当我读取每个数据块时,我会重置计时器。如果计时器在我可以读取块之前到期,我认为网络已经停止,我会中断线程并重新开始该请求。

我已经这样做了,它确实通过至少减少了我在继续请求之前必须等待的延迟来改善事情,因为我不必等待可能需要很长时间的 TCP 超时。

中断当前的 I/O 操作并重新启动似乎可以使网络恢复活力一段时间,通常运行良好几分钟,然后再次停止。我在调试时将档位记录到控制台,我得到了相当多的档位。

这是一个非常奇怪的问题,我对失速检测解决方案并不完全满意。这似乎只是掩盖了问题,但它确实让我能够在一定程度上解决我遇到的长期延误问题。

【讨论】:

    【解决方案4】:

    我认为在我使用过的所有 BlackBerry 操作系统(从 4.5 到 6.0)上,read(byte[], int, int) 的实现存在错误。
    我为 InputStream 编写了一个适配器,它将read(byte[], int, int) 转换为对read() 的一次调用,并解决了我正在开发的应用程序中的流挂起问题。

    如果您阅读 read(byte[], int, int) 的 RIM 规范,它会说:

    InputStream 类的 read(b, off, len) 方法只是重复调用方法 read()。如果第一个此类调用导致 IOException,则该异常会从对 read(b, off, len) 方法的调用中返回。如果对 read() 的任何后续调用导致 IOException,则捕获该异常并将其视为文件结尾;到目前为止读取的字节存储在 b 中,并返回发生异常之前读取的字节数。鼓励子类提供此方法的更有效实现。

    我按照这个规范编写了自己的版本,但遇到了同样的问题。我认为问题在于,一旦某些数据可用,该方法需要返回而不阻塞。做到这一点的唯一方法是使用available() 来查看可以读取多少字节而不阻塞。由于 RIM 文档没有提到 available() 的使用,我认为它只是调用 read() 直到缓冲区已满或 read() 返回 -1。如果您的数据以少量突发形式出现,这可能需要很长时间。如果那个“长时间”超过了连接超时,连接就会终止。

    这是我使用的代码,它解决了挂起的连接问题:

    public int read(byte[] bts, int st, int len) throws IOException {
        if(len == 0) {
            return 0;
        }
        int readByte = this.read();
        if(readByte == -1) {
            return 0;
        }
        bts[st] = (byte)readByte;
        return 1;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-09
      • 2013-10-23
      • 1970-01-01
      • 2018-08-05
      相关资源
      最近更新 更多