我需要用 qt 下载大量文件(通常不小)(也计算速度和显示进度),目前我为此使用 QnetworkAccessManager,但是在大量快速下载时它会随机崩溃,最常见的是 ntdll.dll!tan on堆栈,谷歌说它来自win api的堆分配,我在这个代码部分没有做任何手动内存管理,所以我认为我的代码不能做内存损坏,我也试图不删除 qnetworkreply 对象,这也是不解决崩溃,这里是代码部分:
请求:
QNetworkReply *r = qnm.get(req);
connect(r, SIGNAL(downloadProgress(qint64,qint64)), SLOT(game_s_file_download_progress(qint64,qint64)), Qt::QueuedConnection);
connect(r, SIGNAL(finished()), &conn_timer, SLOT(stop()), Qt::QueuedConnection);
connect(r, SIGNAL(finished()), SLOT(game_sz_file_request_finished()), Qt::QueuedConnection);
connect(r, SIGNAL(downloadProgress(qint64,qint64)), &conn_timer, SLOT(start()), Qt::QueuedConnection);
connect(r, SIGNAL(downloadProgress(qint64,qint64)), spd_calc_obj, SLOT(handle_new_data(qint64,qint64)), Qt::QueuedConnection);
conn_timer_obj *ct = new conn_timer_obj(0, r);
connect(r, SIGNAL(finished()), ct, SLOT(deleteLater()), Qt::QueuedConnection);
connect(&conn_timer, SIGNAL(timeout()), ct, SLOT(abort()), Qt::QueuedConnection);
connect(&conn_timer, SIGNAL(timeout()), &conn_timer, SLOT(stop()));
conn_timer.start();
(qnm 是 QnetworkAccessManager)
处理数据:
lists_mutex.lock();
QNetworkReply *current_file = qobject_cast<QNetworkReply*>(sender());
assert(current_file != NULL);
#ifdef DEBUG
try{
#endif
if(current_file->error() == QNetworkReply::NoError)
{
if(!updated_size_c_f)
updated_size_c_f = updated_size_c_f_completed + bytesTotal;
QString filename = cfg->game_path();
if(!updated_g_s_list_http.empty())
{
filename += QString::fromUtf8(updated_g_s_list_http.begin()->name.c_str());
if(filename.indexOf("/l10n/") != -1)
{
int p1 = 0, p2 = 0;
p1 = filename.indexOf("/l10n/");
p1+= strlen("/l10n/");
p2 = filename.indexOf("/", p1+1);
filename.remove(p1, p2-p1);
}
}
else
filename += QString("/upd/" + QString::fromUtf8(updated_g_f_list.begin()->path.c_str()));
updated_size_completed_mutex.lock();
updated_size_completed += current_file->bytesAvailable();
updated_size_c_f_completed += current_file->bytesAvailable();
emit set_progress2(((double)updated_size_completed/(double)updated_size)*100.0);
QFile file(filename + ".upd_part");
if(file.open(QIODevice::WriteOnly | QIODevice::Append))
{
file.write(current_file->readAll());
file.close();
}
else
current_file->abort();
if(!partial_pak_downloading)
emit set_progress(((double)updated_size_c_f_completed/(double)updated_size_c_f)*100.0);
updated_size_completed_mutex.unlock();
}
else
{
#ifdef DEBUG
cfg->log()<<current_file->errorString();
#endif
current_file->abort();
}
#ifdef DEBUG
}
catch(...)
{
cfg->log()<<"exception in game_s_file_download_progres: ";
lists_mutex.unlock();
}
#endif
lists_mutex.unlock();
}
和完成的信号:
QNetworkReply *current_file = qobject_cast<QNetworkReply*>(sender());
assert(current_file != NULL);
lists_mutex.lock();
current_file->disconnect();
conn_timer.disconnect();
QString filename = cfg->game_path();
#ifdef DEBUG
try{
#endif
if(!updated_g_s_list_http.empty())
{
#ifdef DEBUG
upd_stats.incr_d_h();
#endif
filename += QString::fromUtf8(updated_g_s_list_http.begin()->name.c_str());
if(filename.indexOf("/l10n/") != -1)
{
int p1 = 0, p2 = 0;
p1 = filename.indexOf("/l10n/");
p1+= strlen("/l10n/");
p2 = filename.indexOf("/", p1+1);
filename.remove(p1, p2-p1);
}
}
else
{
assert(!updated_g_f_list.empty());
filename += QString("/upd/" + QString::fromUtf8(updated_g_f_list.begin()->path.c_str()));
}
#ifdef DEBUG
}
catch(...)
{
cfg->log()<<"exception in game_sz_file_request_finished part 1: ";
}
#endif
if(current_file->error() == QNetworkReply::NoError)
{
#ifdef DEBUG
try{
#endif
fail_dl_count = 0;
int have_bytes = current_file->bytesAvailable();
if(have_bytes)
{
updated_size_completed_mutex.lock();
updated_size_completed += have_bytes;
emit set_progress2(((double)updated_size_completed/(double)updated_size)*100.0);
updated_size_completed_mutex.unlock();
QFile file(filename + ".upd_part");
if(file.open(QIODevice::WriteOnly | QIODevice::Append))
{
file.write(current_file->readAll());
file.close();
}
else
;//TODO: handle error
}
更新1:
我在 qt bugtracker 上发布了错误,它也链接了具有相同问题的错误: