使用Qt通过蓝牙发送多个原始数据包

时间:2018-01-21 14:23:15

标签: python c++ qt sockets bluetooth

我写了这段Python代码(使用pybluez)通过L2CAP发送原始BNEP蓝牙数据包。目的是做一些模糊测试。

 BNEP_PSM = 0x000F
 btSock = bluetooth.BluetoothSocket(bluetooth.L2CAP)
 btSock.connect(('<some BDADDR>', BNEP_PSM))

 for i in range(10):
    btSock.send('<some payload>')

即使有效负载格式错误,也可以正常工作,并且正如预期的那样创建多个BNEP数据包。

现在,我正在尝试使用Qt在C ++中编写相同的函数,但它的工作方式不同。代码的摘录如下:

QBluetoothSocket btSock(QBluetoothServiceInfo::L2capProtocol);
btSock.connectToService(QBluetoothAddress("<some BDADDR>"), QBluetoothUuid::Bnep);

QObject::connect(&btSock, &QBluetoothSocket::connected, [&btSock](){
    int i = 10;
    while (i--)
        btSock.write("<some payload>");
});

使用i = 1运行它可以很好地发送具有指定有效负载的单个数据包。 使用i = 10运行将导致单个数据包,其有效负载等于指定有效负载的十倍

例如,在循环3中设置“AAAA”的有效负载将导致第一种情况使用Python

+------------+----+       +------------+----+       +------------+----+
|L2CAP Header|AAAA|  -->  |L2CAP Header|AAAA|  -->  |L2CAP Header|AAAA|
+------------+----+       +------------+----+       +------------+----+

在第二种情况下使用Qt

+------------+------------+
|L2CAP Header|AAAAAAAAAAAA|
+------------+------------+

我怎么能强迫Qt套接字write表现得像Python套接字send

UPDATE:

查看文档说明

  

当控制返回事件循环时写入字节

如何在返回事件循环之前强制缓冲区刷新?

2 个答案:

答案 0 :(得分:2)

  

如何在返回事件循环之前强制缓冲区刷新?

你不能,因为发送只能异步完成,而不是同步。

但我们可以按照数据包排队的方式对刷新进行排队。即:在发送前一个数据包之后发送每个数据包。因此,每当事件循环处理完所有其他工作时,我们将发送它。这个成语是零持续时间计时器 - 请注意,这与计时器没有任何关系,它是计时器概念的一个奇怪的重载,否则真的没有意义。

int i = 10;
while (i--)
  QTimer::singleShot(0, this, [this]{ m_btSocket.write("<some payload>"); });

m_btSocket必须是该类的成员,并且必须是值成员 - 否则代码将是不安全的。

如果您希望确保在断开连接时转储过时的数据包并且不会影响任何后续连接,请跟踪它们的生成并仅在其当前发送时发送:

class Foo : public QObject {
  unsigned int m_generation = {}; // unsigned: modulo math w/o overflows
  QBluetoothSocket m_btSocket{QBluetoothServiceInfo::L2CAP};
  ...
  bool isBtConnected() const { return m_btSocket::state() == QBluetoothSocket::ConnectedState; }
  void sendSinglePacket(const QByteArray & data) {
    if (!isBtConnected()) return;
    auto gen = m_generation;
    QTimer::singleShot(0, this, [this, gen, data] {
      if (m_generation == gen)
        m_btSocket.write(data);
    });
  }
  Foo(QObject * parent = {}) : QObject(parent) {
    connect(&m_btSocket, &QBluetoothSocket::Disconnected, this, [this]{
      m_generation++; // drops all in-flight packets
    });
    ...
  }
};

答案 1 :(得分:0)

我没有找到使用QBluetoothSocket方法的正确解决方案,但是我使用了一点点黑客。

刚刚使用过C标头sys/socket.h(我需要支持仅符合POSIX标准的操作系统)并更改了

btSock.write("<some payload>");

send(btSock.socketDescriptor(), "<some payload>", <payload length>);