【问题标题】:Freeze on sending large file using QTcpSocket冻结使用 QTcpSocket 发送大文件
【发布时间】:2014-07-15 16:42:09
【问题描述】:

我正在尝试从一台 PC 向另一台 PC 发送和接收一些大文件(至少 16GB)。 当客户端应用程序收到大约 2GB 的内存并且它几乎消耗了我所有的内存(也用完了大约 2GB 的内存)时,应用程序冻结了。我在服务器端没有这个问题。

这是发送文件的服务器代码

clock_t startTime = clock();
QTcpSocket *clientConnection = tcpServer->nextPendingConnection();
connect(clientConnection, SIGNAL(disconnected()),
            clientConnection, SLOT(deleteLater()));

QString sourceFileName("/path/to/source/sourcefile.big");
QByteArray baFName=sourceFileName.toLocal8Bit();
char* c_fileName=baFName.data();

char buf[BUFSIZ];
size_t size;
unsigned long long sendSize=0;
int source = open64(c_fileName, O_RDONLY, 0);
unsigned long long loopCount=0;
while ((size = read(source, buf, BUFSIZ)) > 0) {
    sendSize=clientConnection->write(buf, size);
    clientConnection->waitForBytesWritten();
    if(sendSize< size) {
       qWarning("transmit error!");
    }
    qDebug() << "Loop #" << ++loopCount << " send data: " << sendSize;

}

qDebug() << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds.";

clientConnection->disconnectFromHost();

应用程序的客户端已经知道它接收到的文件有多大,这里是接收文件并将其写入磁盘的代码

clock_t startTime = clock();

QString sourceFileName("/path/to/target/targetfile.big");
unsigned long long targetSize=16447314864ULL;

unsigned long long loopCount=(targetSize / 8192ULL) + ( targetSize % 8192ULL > 0 ? 1 : 0);
QByteArray baFName=sourceFileName.toLocal8Bit();
char* c_fileName=baFName.data();

char buf[BUFSIZ];
size_t size;
unsigned long long sendSize=0;
int dest = open64(c_fileName, O_WRONLY | O_CREAT, 0644);

while (loopCount){
    if (tcpSocket->waitForReadyRead()){
        size=tcpSocket->read(buf, 8192);
        write(dest, buf, size);
        qDebug() << "Loop #" << loopCount << " receive data: " << size;
        loopCount--;
    }
}

qDebug() << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds.";

如果重要的话,我使用的是 ubuntu 14.04。

【问题讨论】:

    标签: c++ qt ubuntu qtcpsocket qtcpserver


    【解决方案1】:

    我已经设法解决了客户端的冻结和内存占用问题。 事实证明,waitForReadyRead() 是它的原因。

    我只是删除它并检查 tcpSocket->read 的输出。如果它是零,那么我会延迟几毫秒,这样这次它就不会成为处理器的霸主了。

    我想知道如果我删除 waitForByteWritten(),服务器端是否会更快。我试图检查 clientConnection->bytesToWrite() 并将其限制为 1GB,但事实证明这个数字没有下降。还有其他方法可以用来同步替换 waitForByteWritten() 吗?

    【讨论】:

    • 另外,我已经检查了 clientconnection->write 的输出,但它总是返回与 size 相同的值,而不是 -1。
    【解决方案2】:

    最好的方法是通过将套接字的readyRead()信号连接到一个槽来以异步模式接收数据:

    connect( tcpSocket, SIGNAL(readyRead()),
            this, SLOT(tcpReady()) );
    

    来自 Qt 文档:

    每次有新数据可用时,都会发出一次此信号 从设备读取。它只会在有新数据时再次发出 可用,例如当网络数据的新负载到达时 在你的网络套接字上,或者当一个新的数据块被附加时 到您的设备。

    您可以在连接到readyRead信号的插槽中读取数据:

    void MyClass::tcpReady()
    {
        unsigned long long bytesAvailable = tcpSocket->bytesAvailable();
        char buf[bytesAvailable];
        totalBytesRead += bytesAvailable;
        write(dest, buf, size);
        qDebug() << "Loop #" << loopCount << " receive data: " << size;
    
    }
    

    【讨论】:

      【解决方案3】:

      您应该从摆脱 loopCount 开始。比较接收的字节数和要接收的字节数。

      您还需要使用 tcpSocket->bytesAvailable()

      你可能想试试这段代码:它可能会给你一个大致的想法。

      unsigned long long totalBytesRead = 0;
      while (totalBytesRead < targetSize) {
          if (tcpSocket->waitForReadyRead()) {
                  unsigned long long bytesAvailable = tcpSocket->bytesAvailable();
                  char buf[bytesAvailable];
                  totalBytesRead += bytesAvailable;
                  write(dest, buf, size);
                  qDebug() << "Loop #" << loopCount << " receive data: " << size;
          }
      }
      

      另外,由于您正在编写 QT 代码,您可能希望使用 QFile。它还可以为您省去这样的麻烦:

      char* c_fileName=baFName.data();
      

      你可以用这个代替

      QFile file("/path/to/target/targetfile.big");
      

      【讨论】:

        猜你喜欢
        • 2013-05-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-19
        • 2012-11-27
        • 1970-01-01
        • 1970-01-01
        • 2018-09-01
        相关资源
        最近更新 更多