BlackBerry OS 5上的网络I / O挂起

时间:2010-07-08 19:50:26

标签: java blackberry inputstream java-me

我的BlackBerry 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
  • Tour 9630
  • Bold 9000
  • Pearl 9100
  • 曲线8530

我有一个Curve 8530和Storm 9550设备,它也会出现在这两个设备上。

任何帮助都将不胜感激。

4 个答案:

答案 0 :(得分:0)

您可能想尝试使用Available()方法。即使您在一个反向线程上序列化数据,看起来请求也是在主线程中创建的。你可能会遇到一些奇怪的竞争条件。

答案 1 :(得分:0)

您是否可以添加一些日志记录来显示设备选择用于每个连接的传输类型?也许这是传输选择API选择它认为可以工作的传输的情况,而事实上并非如此。

答案 2 :(得分:0)

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

我已经完成了这项工作,它确实通过至少减少我必须等待的延迟来改善事情,因为我不必等待TCP超时,这可能需要很长时间。< / p>

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

这是一个非常奇怪的问题,我对失速检测解决方案并不满意。它似乎只是掩盖了这个问题,但它确实让我能够解决我所得到的长时间延迟。

答案 3 :(得分:0)

我认为在我使用的所有BlackBerry操作系统上read(byte[], int, int)的实施存在一个错误 - 4.5到6.0。 我为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;
}