qnetworkaccessmanager上传失败时,qnetworkreply::error()返回枚举值,如operationcancelederror、timeouterror、connectionrefusederror、remotehostclosederror等,需在finished()槽中检查,不可与errno混用,且须结合http状态码综合判断。

上传文件时遇到网络异常,C++本身不提供自动重试、断点续传或连接恢复能力——你得自己写逻辑,否则std::bad_alloc、ECONNRESET或ETIMEDOUT一出现,程序就卡死或崩溃。
QNetworkAccessManager 上传失败时,QNetworkReply::error() 返回什么?
QT 的 QNetworkAccessManager 在上传失败后不会抛异常,而是通过 QNetworkReply::error() 返回枚举值,常见有:QNetworkReply::OperationCanceledError(主动取消)、QNetworkReply::TimeoutError(超时)、QNetworkReply::ConnectionRefusedError(服务端拒绝)、QNetworkReply::RemoteHostClosedError(连接被服务器关闭)。注意:这些值和系统 errno 不同,不能直接用 strerror(errno) 解释。
必须在 finished() 信号槽中检查:
connect(reply, &QNetworkReply::finished, [=]() {
if (reply->error() != QNetworkReply::NoError) {
qDebug() errorString();
// 这里做重试或降级处理
}
});
容易踩的坑:reply->error() 在 finished() 触发前可能还是 NoError,不能在发送后立刻查;也不能只依赖 httpStatusCode,比如 502/504 错误时 error() 可能仍是 NoError,得额外检查 reply->attribute(QNetworkRequest::HttpStatusCodeAttribute)。
大文件上传触发 std::bad_alloc 怎么办?
cpp-httplib 或手写 socket 上传大文件时,如果一次性把整个文件读进内存(如用 std::ifstream::read + std::string),很容易触发 std::bad_alloc。这不是网络异常,但会中断上传流程。
- 改用流式分块上传:每次只读
64KB到栈缓冲区,调用write()发送,再循环 - 避免
std::string存整个文件体;改用std::vector<char></char>并 reserve 合理大小(如 1MB) - 对 QT 的
QHttpMultiPart,不要把整个文件塞进QHttpPart::setBody(),而应使用QHttpPart::setBodyDevice()绑定QFile实例
示例(QT 流式上传):
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
QFile *file = new QFile("large.zip");
file->open(QIODevice::ReadOnly);
QHttpPart part;
part.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
part.setBodyDevice(file); // 关键:不加载全文本到内存
file->setParent(reply); // 让 reply 管理 file 生命周期
如何判断是临时性网络抖动,还是永久性失败?
不能单靠一次失败就放弃。需结合错误类型、HTTP 状态码、重试次数和退避策略综合判断:
-
TimeoutError、HostNotFoundError、RemoteHostClosedError倾向于可重试(最多 3 次,间隔 1s/2s/4s) -
AuthenticationRequiredError、InternalServerError(500)、BadGatewayError(502)建议暂停重试,记录日志并通知用户 - 连续两次
ConnectionRefusedError,大概率是服务端宕机,应跳过重试直接报错
注意:重试时要重新构造 QNetworkRequest 和 QHttpMultiPart,因为 QNetworkReply 对象不可复用;且每次重试需生成新 boundary,否则 multipart 解析会出错。
socket 层上传时,send() 返回 -1 后怎么查具体原因?
底层 socket 上传失败时,send() 返回 -1,此时必须立刻读 errno,而不是看返回值本身:
-
EAGAIN/EWOULDBLOCK:非阻塞 socket 缓冲区满,应等待POLLOUT事件后重试 -
EPIPE:对端已关闭连接,不能再发,应终止上传 -
ENOTCONN:socket 未连接,需重建连接 -
ETIMEDOUT:发送超时,通常意味着链路中断,需重连
关键代码模式:
ssize_t n = send(sockfd, buf, len, MSG_NOSIGNAL);
if (n == -1) {
switch (errno) {
case EAGAIN:
case EWOULDBLOCK:
// 注册 POLLOUT,稍后重试
break;
case EPIPE:
case ENOTCONN:
// 清理资源,标记上传失败
break;
default:
// 其他错误(如 ENOMEM)一般不可恢复
break;
}
}
真正麻烦的是:错误边界模糊——比如 EAGAIN 和 ETIMEDOUT 可能同时发生,而重试逻辑若没区分清楚,就会陷入无限等待或反复失败。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










