【发布时间】:2017-09-05 22:56:48
【问题描述】:
我正在编写一个程序,以使用 Qt_5.9 在 C++ 中通过本地网络在客户端和服务器之间发送文件,并且传输随机停止(有时约为 400MB,但有时会更少)。
下面是在socket上写入文件内容的方法(在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 没有发出),但服务器仍然写入其中(在任务管理器中,我可以看到内存使用量增加)。
谁能告诉我我做错了什么? (除了存在 FTP 时使用 TCP 进行文件传输)
我尝试在write_file 方法中插入clientConnection->waitForReadyRead(X),但无论套接字状态如何,它总是等待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 信号连接到只发送文件的一小部分的方法),同样适用:在某些时候,似乎发生了拥塞......
【问题讨论】:
-
据我所知,您没有检查连接是否处于活动状态。
-
@macroland 显然至少是在传输开始的时候,但是我怎样才能确保它保持活跃呢?
-
您需要在服务器/客户端之间为自己创建一个
keepAlive,例如每 500 毫秒。 -
你能解释一下这部分吗:`我可以看到内存使用增加`应该是套接字缓冲区,而不是内存(RAM)
-
@Rafalon 请阅读:doc.qt.io/qt-5/qabstractsocket.html 关注功能:
setReadBufferSize(qint64 size)或qint64 readBufferSize() const