背景:

我有下面的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数据包的C代码:hi0,hi1,... hi19:
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更新?

最佳答案

我希望在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());

07-24 09:45
查看更多