使用QTcpSocket冻结发送大文件

时间:2014-05-26 21:39:05

标签: c++ qt ubuntu qtcpsocket qtcpserver

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

3 个答案:

答案 0 :(得分:1)

你应该从摆脱loopCount开始。将接收的字节数与要接收的字节数进行比较。

您还需要使用tcpSocket-&gt; 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");

答案 1 :(得分:1)

最好的方法是通过将套接字的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;

}

答案 2 :(得分:0)

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

我只是删除它并检查tcpSocket-&gt;读取的输出。如果它为零,那么我会延迟几毫秒,这样它就不会成为处理器生猪了。

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