Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/blackberry/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java BlackBerry OS 5上的网络I/O挂起_Java_Blackberry_Inputstream_Java Me - Fatal编程技术网

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

Java BlackBerry OS 5上的网络I/O挂起,java,blackberry,inputstream,java-me,Java,Blackberry,Inputstream,Java Me,我在黑莓操作系统5上的网络I/O代码有一些问题 在I/O操作过程中,我不断地遇到零星挂起,最终出现TCP超时异常 我使用5.0网络API建立连接,每次都能完美地工作 问题是在执行实际I/O时。我有一个后台工作线程,为队列中的I/O请求提供服务。只有一个后台线程,因此所有请求都序列化到此线程上 完成通知通过委托接口完成,委托接口在请求排队时传入 在后台工作线程上调用完成委托,但是客户端可以通过invokeLater将其重新发布到事件线程,以进行UI更新等 备注: HttpRequest是我自己的类

我在黑莓操作系统5上的网络I/O代码有一些问题

在I/O操作过程中,我不断地遇到零星挂起,最终出现TCP超时异常

我使用5.0网络API建立连接,每次都能完美地工作

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

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

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

备注:
HttpRequest是我自己的类,它保存有关请求的数据。
MutableData是我自己的类,它保存读取的数据。
缓冲区大小=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超时错误。 如果这种情况偶尔发生,我会把它归为正常的网络拥塞,但它不会发生 频繁发生足以表明存在更深层次的问题

编辑:

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

  • 风暴9550
  • 旅游9630
  • Bold 9000
  • 珍珠9100
  • 曲线8530
我有一个Curve 8530和Storm 9550设备,这两个设备上都有


任何帮助都将不胜感激。

您可能想试试这种方法。即使您在一个反向线程上序列化数据,看起来请求是在主线程中创建的。您可能会遇到一些奇怪的竞争情况。

您是否可以添加一些日志来显示设备选择用于每个连接的传输类型?可能是传输选择API选择了一个它认为可以工作的传输,而实际上它不能工作。

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

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

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


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

我认为在我使用过的所有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;
}

这是在模拟器中还是在真实设备中?添加了设备和模拟器信息。我问这个问题的原因是因为我发现5.0模拟器在网络仿真方面有很多缺陷-通常没有明显的原因而挂起连接。然而,既然你在真实的设备上也看到了它,那一定是不一样的。每次它选择TRANSPORT\u TCP\u CELLULAR时。我还以为我可能会遇到一个奇怪的竞争条件,但就我的一生而言,我找不到一个。唯一的共享数据是请求队列,它在发布线程和处理线程之间正确同步。