4

我正在尝试从一台 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。

4

3 回答 3

2

最好的方法是通过将 socket 的 readyRead() 信号连接到 slot 以异步模式接收数据:

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;

}
于 2014-05-27T06:13:25.630 回答
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");
于 2014-05-27T01:03:51.743 回答
0

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

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

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

于 2014-05-27T09:33:08.023 回答