【问题标题】:BluetoothSocket OutputStream.write() issueBluetoothSocket OutputStream.write() 问题
【发布时间】:2016-12-22 10:40:33
【问题描述】:

我使用修改后的Google Bluetooth Chat 应用程序在两个 Android 设备(Android 5 和 Android 6)之间进行客户端-服务器蓝牙 RFCOMM 通信。

我的客户端应用有一些代码:

private class ConnectedThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final BufferedInputStream mmInStream;
    private final BufferedOutputStream mmOutStream;

    private ByteBuffer outputBuffer = null;

    private int currentOperation = 0;

    private byte currentMessageType = 0;

    ConnectedThread(BluetoothSocket socket) {
        Log.d(LOG_TAG, "create ConnectedThread: Insecure");
        mmSocket = socket;
        BufferedInputStream tmpIn = null;
        BufferedOutputStream tmpOut = null;

        try {
            tmpIn = new BufferedInputStream(socket.getInputStream());
            tmpOut = new BufferedOutputStream(socket.getOutputStream());
        } catch (IOException e) {
            Log.e(LOG_TAG, "temp sockets not created", e);
        }

        mmInStream = tmpIn;
        mmOutStream = tmpOut;
        setState(STATE_CONNECTED);
    }
    public void run() {
        Log.i(LOG_TAG, "BEGIN mConnectedThread");
        byte[] buffer;
        ByteBuffer intBuf;
        int tempInt;

        while (mState == STATE_CONNECTED) {
            try {
                if(mmInStream.available()>8) {
                    Log.i(LOG_TAG, mmInStream.available() + " f");
                    buffer = new byte[9];
                    mmInStream.read(buffer, 0, 9);

                    intBuf = ByteBuffer.wrap(buffer);
                    Log.i(LOG_TAG, "NEW MESSAGE: "+intBuf.getInt()+" "+intBuf.get()+" "+intBuf.getInt());
                    intBuf.rewind();

                    tempInt = intBuf.getInt();
                    Log.i(LOG_TAG, tempInt + " GET OP ID " + intBuf.capacity());

                    currentMessageType = intBuf.get();
                    Log.i(LOG_TAG, currentMessageType + " GET OP TYPE");
                    
                    // ... some more code
                }
            }
            catch (IOException err ) {
                Log.e(LOG_TAG, "disconnected", err);
                connectionLost();
                break;
            }
        }
    }
    void write(byte[] data) {
        try {
            Log.i(LOG_TAG, "WRITE NEW MESSAGE: "+data.length);

            mmOutStream.write(data);
            SystemClock.sleep(200);
            
        } catch (IOException e) {
            Log.e(LOG_TAG, "Exception during write", e);
        }
    }
    void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) {
            Log.e(LOG_TAG, "close() of connect socket failed", e);
        }
    }

这部分管理蓝牙套接字的读/写操作。

那么问题是什么?当我发送大小为 (字节数组)的数据时,一切正常。但随后我尝试发送一些大数据(>10000 字节)并收到此消息(使用 LogCat):

12-22 12:53:49.849 28177-28177/com.lukanin.testappjava2 I/(BLUETOOTH): DATA LENGTH: 35722 OPT ID: 1 TYPE: 11
12-22 12:53:49.849 28177-28177/com.lukanin.testappjava2 I/(BLUETOOTH): SEND DATA: 1 11 35722
12-22 12:53:49.849 28177-28177/com.lukanin.testappjava2 I/(BLUETOOTH): WRITE NEW MESSAGE: 35731
                                                                       
[ 12-22 12:53:49.849 21464:21536 D/         ]
PORT_WriteDataCO: tx queue is full,tx.queue_size:10890,tx.queue.count:11,available:14941
                                                                       
[ 12-22 12:53:49.959 21464:21536 D/         ]
PORT_WriteDataCO: tx queue is full,tx.queue_size:10890,tx.queue.count:11,available:3061

我认为有某种 OutputStream 溢出,但我不明白如何修复它。我应该怎么做才能防止这种情况发生?有什么方法可以检查 OutputStream 的写入可用性吗?

附:这种情况与 Android 5 相关(在 Android 6 上似乎一切正常)。

【问题讨论】:

  • 我不明白到底是什么问题,但是看看在写入数据后添加一个 mmOutStream.flush() 是否有帮助。
  • 通过您编写的 logcat 示例,我无法察觉问题。你能解释得更好吗?
  • 不。我试过这样的解决方案。在这种情况下,我只收到 PORT_WriteDataCO: tx queue is full... 错误之一。
  • 不确定,但 tx.queue_size 只有 10890。如果你发送更多它会溢出。
  • 我找到了一些关于它的信息:http://kb.vector.com/entry/360/。反正有没有可能接收到 tx queue 的可写容量?

标签: java android sockets bluetooth


【解决方案1】:

我不确定这是否会有所帮助,但请尝试分块写入:

private static funal int CHUNK_SIZE = 200;

.....

int currentIndex = 0;
int size = data.length; 
while (currentIndex < size) {
    int currentLength = Math.Min(size-currentIndex, CHUNK_SIZE);
    memOutStream.write(data, currentIndex, currentLength);
    currentIndex += currentLength; 
}

【讨论】:

  • 它可以完美地处理小数据。但是还是不能发送大字节数组(溢出终于还是存在的)。
【解决方案2】:

在 Android 5 中,

  /* if we're over buffer high water mark, we're done */
        if ((p_port->tx.queue_size  > PORT_TX_HIGH_WM)
         || (p_port->tx.queue.count > PORT_TX_BUF_HIGH_WM))
        {
            port_flow_control_user(p_port);
            event |= PORT_EV_FC;
            debug("tx queue is full,tx.queue_size:%d,tx.queue.count:%d,available:%d",
                    p_port->tx.queue_size, p_port->tx.queue.count, available);
            break;
         }

我不知道 PORT_TX_HIGH_WMPORT_TX_BUF_HIGH_WM 的值,但假设此 tx.queue_size 大于您可以发送的最大值.

https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/android-5.0.0_r3/stack/rfcomm/port_api.c

【讨论】:

  • 感谢您提供信息。或许你知道是否有可能接收到当前可写的 tx queue 容量?
  • 在 Android 中我不知道。只找到这篇解释MTU是如何发现的文章,但这是非常低级的:blog.csdn.net/wendell_gong/article/details/45060337
  • 我发现 PORT_TX_BUF_HIGH_WM = 4,但是 PORT_TX_HIGH_WM 计算复杂,但不应该大于 1691。这是 Android 代码中的常量。但这取决于硬件、制造商和 Android 版本。
猜你喜欢
  • 1970-01-01
  • 2014-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-09
  • 2013-02-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多