如何防止文件传输被中断(通过TCP)

时间:2017-08-30 07:04:13

标签: c++ qt tcp

我正在编写一个程序,通过Qt_5.9在C ++中通过本地网络在客户端和服务器之间发送文件,并且传输随机停止(有时大约400MB,但有时会少一些)。

以下是在套接字上编写文件内容的方法(在 servertcp.cpp 中):

void ServerTcp::write_file(QString fileName){
    QFile file(fileName);
    if(file.open(QIODevice::ReadOnly)){
        qint64 nb = 0;
        while(nb < file.size()){
            QByteArray partial = file.read(65536);
            clientConnection->write(partial, partial.count());
            // I think I have to write something here
            qint64 nbb = partial.count();
            nb += nbb;
            qDebug() << nbb << " (" << nb << ")";
        }

        file.close();

        clientConnection->write("[[[END]]]");
    }
}

这是方法读取(发出readyRead时调用)套接字(在 clienttcp.cpp 中):

void ClientTcp::read()
{
    qDebug() << "To read : " << soc.size();

    emit to_IHM_text(soc.readAll());
}

我面临的问题是,在某些时候,客户端停止阅读套接字(意味着我们不再进入read方法,所以我猜readyRead不是&#39; t),但服务器仍在其中写入(在任务管理器中,我可以看到内存使用增加)。

谁能告诉我自己做错了什么? (除了在FTP存在时使用TCP进行文件传输) 我尝试在clientConnection->waitForReadyRead(X)方法中插入write_file,但无论套接字状态如何,它总是等待X ms。

编辑:

所以我更新了write_file方法以检查连接状态:

void ServerTcp::write_file(QString fileName){
    QFile file(fileName);
    if(file.open(QIODevice::ReadOnly)){
        qint64 nb = 0;
        while(nb < file.size()){
            QByteArray partial = file.read(65536);

            if(clientConnection->bytesToWrite()>0){
                problem = true;
                qDebug() << clientConnection->bytesToWrite();
                clientConnection->waitForBytesWritten();
            }

            qDebug() << clientConnection->state();
            qint64 nbb = clientConnection->write(partial, partial.count());
            nb += nbb;
            qDebug() << nbb << " (" << nb << ")";
        }

        file.close();

        clientConnection->write("[[[END]]]");
    }
}

在所有文件传输过程中始终会提示QAbstractSocket::ConnectedState,这意味着问题出在其他地方。

显然,即使clientConnection->write(...)总是返回65536(文件的最后一个块除外),套接字也会随机拒绝有效地写入字节(因为clientConnection->bytesToWrite()会在一段时间后返回65536的倍数)。

关于客户端知道它接收整个文件的方式,我使用自制握手,分开发送的标头(文件名+大小)和响应(可以接收或不接收)。

编辑2:

我尝试了另一种方法(将套接字bytesWritten信号连接到仅发送文件的一小部分的方法),同样适用:在某些时候,似乎发生了拥塞......

1 个答案:

答案 0 :(得分:0)

From your revised code:

let calendar = Calendar.current
let startTimeComponent = DateComponents(calendar: calendar, hour: 8)
let endTimeComponent   = DateComponents(calendar: calendar, hour: 17, minute: 30)

let now = Date()
let startOfToday = calendar.startOfDay(for: now)
let startTime    = calendar.date(byAdding: startTimeComponent, to: startOfToday)!
let endTime      = calendar.date(byAdding: endTimeComponent, to: startOfToday)!

if startTime <= now && now <= endTime {
    print("between 8 AM and 5:30 PM")
} else {
    print("not between 8 AM and 5:30 PM")
}

Have you gamed out what happens when write() returns a smaller value than partial.count(), above?

If not, I'll give you an example. Say write() return 32000 rather than 65536. That mean the first 32000 bytes of your 65536-byte QByteArray went out to the TCP socket; what happens to the remaining 33536 bytes? Nothing, that's what -- they simply get ignored and never go out to the client at all. Therefore the data the client receives will only be part of the data the original file contained, because the data-stream is missing arbitrary chunks from various places in the middle of the file. That's probably not the behavior you want.

The fix to handle the short-write() problem would be to call write() again with just the remaining 32000 bytes of data (and repeat as necessary until all of the bytes in the partial-buffer have actually been handed off to the socket-buffer, as indicated by the results of the write() calls). Then, and only then, is it time to read more data from the file to send.