网络I/O挂在BlackBerry OS 5上

问题描述:

我的BlackBerry OS 5上的网络I/O代码有问题。网络I/O挂在BlackBerry OS 5上

在我的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
  • 粗体9000
  • 明珠9100
  • 曲线8530

我有一个曲线8530和Storm 9550设备,它也发生在这两者上。

任何帮助,将不胜感激。

+0

这是在模拟器或真实设备? – 2010-07-08 19:56:56

+0

添加设备和模拟器信息。 – 2010-07-08 21:01:54

+0

我问的原因是因为我发现5.0模拟器在网络仿真方面相当麻烦 - 通常挂起连接没有明显的原因。但是,既然你也在真实设备上看到它,它肯定是不同的。 – 2010-07-08 21:31:13

在其他地方建议在我的网络I/O线程中放置一个失速检测器,并在检测到失速时,中断线程并重新启动请求。我通过在开始请求之前启动一个计时器并在读取每个数据块时重置计时器来实现这一点。如果计时器在我能够读取块之前就已经过期,我假设网络已经停止工作,并且我中断了该线程并重新开始该请求。

我已经完成了这项工作,它至少减少了我必须等待的延迟,因为我无需等待可能需要很长时间的TCP超时,才能继续执行请求。

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

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

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

+0

我还以为我可能会处理一个奇怪的竞争条件,但对于我的生活,我找不到一个。唯一的共享数据是请求队列,并且在发布线程和处理线程之间正确同步。 – 2010-07-09 14:56:46

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

+0

每次它选择TRANSPORT_TCP_CELLULAR。 – 2010-07-08 22:59:50

我认为在我使用的所有BlackBerry操作系统上执行read(byte[], int, int)时存在一个错误 - 4.5至6.0。
我为InputStream编写了一个适配器,将read(byte[], int, int)变成一个调用read(),并解决了我正在处理的应用程序中的流挂问题。

如果你读了RIM规范read(byte[], int, int)它说:

读(B,关闭,LEN)类InputStream的方法简单地调用read()将反复的方法。如果第一次这样的调用导致IOException,那么从调用读取(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; 
}