QTcpSocket发送大文件时出现卡顿问题

4
我正在尝试从一台电脑发送和接收一些大文件(至少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,如果有关的话。
3个回答

2

你需要先摆脱 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");

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;

}

0

我已经成功解决了客户端的卡顿和内存占用问题。原来是waitForReadyRead()引起的。

我只需将其删除并检查tcpSocket->read的输出。如果为零,则延迟几毫秒,以避免成为处理器负担。

我想知道如果我删除waitForByteWritten(),服务器端是否会更快。我尝试检查clientConnection->bytesToWrite()并将其限制为1GB,但发现数字并没有下降。有没有其他方法可以替换waitForByteWritten()以同步方式使用?


另外,我已经检查了clientconnection->write的输出,但它总是返回与size相同的值,从未返回-1。 - Ste

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接