【问题标题】:my C++ code cannot handle (a little bit) fast data traffic我的 C++ 代码无法处理(一点点)快速数据流量
【发布时间】:2014-07-02 15:03:44
【问题描述】:

背景:

我有下面的 C++ 代码监听端口26009 上的 UDP 数据包,然后输出接收到的数据包

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{

    udpSocket.bind(26009); //the port that GUI listens (26009)
    connect(&udpSocket, SIGNAL(readyRead()), this, SLOT(readyRead()));
}


void MainWindow::readyRead(){
    QByteArray datagram;
    do {
      datagram.resize(udpSocket.pendingDatagramSize());
      udpSocket.readDatagram(datagram.data(), datagram.size());
    } while (udpSocket.hasPendingDatagrams());

    qDebug() << "Message: " << datagram;
}

在客户端,这里是unicast 20 udp packet: hi0, hi1, ... hi19 的 C 代码:

int main(void){
    int i;
    char msg[5] = {'\0'};
    for(i=0; i<20; i++){
       snprintf(msg, 4, "hi%d", i);
       send_unicast("192.168.5.1", msg, 26009);
       memset(msg, 0, sizeof msg);
    }
    return 0;
}

void  send_unicast(char IPaddr[16], char* message, uint16_t destPort){
       struct sockaddr_in si_other;
       int s, slen = sizeof(si_other);

      if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1){
        fprintf(stderr, "socket() failed - line817\n");
        exit(1);
      }

      memset((char *) &si_other, 0, sizeof(si_other));
      si_other.sin_family = AF_INET;
      si_other.sin_port = htons(destPort);

      if (inet_aton(IPaddr, &si_other.sin_addr) == 0) {
        fprintf(stderr, "inet_aton() failed - line 825\n");
        exit(1);
      }

      if (sendto(s, message, 512, 0, (struct sockaddr *) &si_other, slen) == -1){
        fprintf(stderr, "sendto() failed - line830\n");
        exit(1);
      }
      close(s);
}

我在不同的 Linux 设备上运行 C++(服务器)和 C(客户端)代码。

问题:

C 代码可以正常工作并生成数据包。我可以在 Wireshark 上看到数据包是在接收端(C++)收到的。

但是,上面的 C++ 代码无法正确接收(或处理)数据包,代码处理速度太快了,我只看到几个输出,例如

hi5
hi14

如果 C 代码的传输频率显着减慢(添加 sleep(1)),则 C++ 代码可以正常输出数据包。

问题:

我使用接收到的 UDP 数据包来更新 GUI (Qt) 上的一些信息。我猜slot 会导致速度变慢,如果我使用pthread 来监听数据包,那么代码会处理流量,但是线程需要如何通知主类以便 GUI 可以相应地更新?

总而言之,您建议如何修改 C++ 代码,使其能够处理快速数据流量并通知 GUI 更新?

【问题讨论】:

    标签: c++ c qt sockets networking


    【解决方案1】:

    在 MainWindow 的 readyRead 函数中,我预计这将是一个问题:-

    QByteArray datagram;
    do {
          qint64 dSize = udpSocket.pendingDatagramSize();
          datagram.resize(dSize);
    
          udpSocket.readDatagram(datagram.data(), dSize);
       } while (udpSocket.hasPendingDatagrams());
    

    如果第一个数据包是 8 个字节长,则将 QByteArray 设置为 8 个字节并读取数据。

    在读取 8 个字节时,如果接收到 6 个字节,则第二次围绕该循环您将在字节数组上调用 resize,但这一次它将它从 8 个字节减少到 6 个并读取 6 个字节,扔掉你之前读入的数据。

    我建议您将数据附加到它,而不是调整 QByteArray 的大小:-

    QByteArray datagram;
    do 
    {     datagram.append(udpSocket.pendingDatagramSize());
          udpSocket.readDatagram(datagram.data(), datagram.size());
    }while (udpSocket.hasPendingDatagrams());
    

    【讨论】:

    • 或者,将qDebug() 输出(和QByteArray)移动到循环体中。我认为从 UDP 附加数据报没有意义,这不是流协议,数据报通常是独立的实体。
    • @UlrichEckhardt,这取决于 OP 想要对数据实际做什么。如果您只想打印出来,那么是的,将其移入体内就足够了。无论哪种方式,问题都是一样的,在显示之前覆盖数据。我见过 UDP 用于流数据,尤其是多人游戏,因为它比 TCP 快。当然还有控制诸如数据包排序之类的事情的要求。
    • 如果我用追加测试它,它会显示 2 个数据包的前几个字节和剩余的第一个字节。总共输出大约 15 个数据包。正如 Ulrich 建议的那样,如果我将 qDebug() 和 QByteArray 添加到循环中,它会输出 20 个数据包,但只输出第一个字节。如果我继续调整大小并将 qDebug() 和 QByteArray 添加到循环中,那么它将正确输出 20 个包含所有字节的数据包。我应该保持调整大小还是使用附加?
    • 我已经更新了答案中的代码。这有帮助吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-30
    • 1970-01-01
    • 2017-08-24
    • 2010-10-31
    • 1970-01-01
    • 1970-01-01
    • 2014-02-19
    相关资源
    最近更新 更多