Russian Qt Forum

Qt => Работа с сетью => Тема начата: Пантер от Январь 24, 2012, 12:34



Название: [НЕ РЕШЕНО] [QNetworkAccessManager] post запрос отправляется 3 раза
Отправлено: Пантер от Январь 24, 2012, 12:34
За код извиняюсь, достался по наследству.
Код
C++ (Qt)
/*
* FileSendDialog.cpp
*
*  Created on: 20.09.2010
*      Author: ****
*/

 
#include <QtCore/QSettings>
#include <QtCore/QFileInfo>
#include <QtCore/QDebug>
 
#include <QtGui/QMessageBox>
 
#include "core.h"
 
#include "FileSendDialog.h"
 
FileSendDialog::FileSendDialog (const QString &fileName, QWidget *parent)
: QProgressDialog (parent), fileName_ (fileName)
{
manager = new QNetworkAccessManager (this);
setWindowTitle (tr ("Send file..."));
//  setCancelButton( 0 );
setWindowModality (Qt::WindowModal);
resize (440, 180);
setStyleSheet ("background-color: #ffffff");
}
 
FileSendDialog::~FileSendDialog()
{
 
}
 
int FileSendDialog::exec()
{
qDebug () << Q_FUNC_INFO;
 
QFile data (fileName_);
 
if (!data.open (QIODevice::ReadOnly)) {
QMessageBox::critical (this,
  tr ("Send..."),
  tr ("Can't open %1 : %2").arg (fileName_)
  .arg (data.errorString()));
return QDialog::Rejected;
}
 
QSettings systemprops (Core::SystemSettingsScope, "Simicon", "converterd");
 
const QString serveraddr = systemprops.value ("serverAddr", "192.168.2.193").toString();
//    QString serveraddr = "127.0.0.1";
const quint16 port = systemprops.value ("serverPort", "8080").toUInt() ;
 
QUrl url;
url.setScheme ("http");
url.setHost (serveraddr);
url.setPort (port);
 
QNetworkRequest request (url);
request.setRawHeader ("Host", QString ("%1:%2").arg (serveraddr).arg (port).toUtf8());
request.setRawHeader ("Connection", "keep-alive");
request.setRawHeader ("Keep-Alive", "300");
request.setRawHeader ("User-Agent", "convertregui");
 
const QByteArray boundaryRegular = "---------------------------193971182219751";
 
request.setRawHeader ("Content-Type",
 "multipart/form-data; boundary=" + boundaryRegular);
 
const QFileInfo fi (fileName_);
 
const QByteArray head = "--" + boundaryRegular + "\r\n"
+ "Content-Disposition: form-data; name=\"out_of_band\"; filename=\""
+ fi.fileName().toUtf8()
+ "\"\r\n"
+ "Content-Type: application/octet-stream\r\n\r\n";
 
const QByteArray tail = "\r\n--"
+ boundaryRegular
+ "--\r\n"
+ QByteArray (10 * 1024, ' ');
 
QNetworkReply *reply = manager->post (request, head + data.readAll () + tail);
 
connect (reply, SIGNAL (uploadProgress (qint64, qint64)),
this, SLOT (uploadProgress (qint64, qint64)));
connect (reply, SIGNAL (finished()),
this, SLOT (replyFinished()));
setWindowTitle (tr ("Send file %1").arg (fi.fileName()));
return QProgressDialog::exec();
}
 
void FileSendDialog::replyFinished()
{
QNetworkReply *reply = qobject_cast <QNetworkReply*> (sender ());
Q_CHECK_PTR (reply);
 
qDebug () << QString ("Reply finished with code %1").arg (reply->error ());
 
if (reply->error() != QNetworkReply::NoError) {
QMessageBox::critical (this,
  tr ("Error..."),
  tr ("Network error: %1").arg (reply->errorString ()));
done (QDialog::Rejected);
} else {
QMessageBox::information (this,
 QString (),
 tr ("File is successfully sent"));
 
done (QDialog::Accepted);
}
 
reply->deleteLater ();
}
 
void FileSendDialog::uploadProgress (qint64 bytesSent, qint64 bytesTotal)
{
qDebug () << QString ("FileSendDialog::uploadProgress %1 from %2")
 .arg (bytesSent)
 .arg (bytesTotal);
setRange (0, bytesTotal + 1);
setValue (bytesSent);
}
 
Вот лог отправки:
Код:
int FileSendDialog::exec() 
"FileSendDialog::uploadProgress 16384 from 246465"
"FileSendDialog::uploadProgress 32768 from 246465"
"FileSendDialog::uploadProgress 49152 from 246465"
"FileSendDialog::uploadProgress 65536 from 246465"
"FileSendDialog::uploadProgress 81920 from 246465"
"FileSendDialog::uploadProgress 98304 from 246465"
"FileSendDialog::uploadProgress 114688 from 246465"
"FileSendDialog::uploadProgress 131072 from 246465"
"FileSendDialog::uploadProgress 147456 from 246465"
"FileSendDialog::uploadProgress 163840 from 246465"
"FileSendDialog::uploadProgress 180224 from 246465"
"FileSendDialog::uploadProgress 196608 from 246465"
"FileSendDialog::uploadProgress 212992 from 246465"
"FileSendDialog::uploadProgress 229376 from 246465"
"FileSendDialog::uploadProgress 245760 from 246465"
"FileSendDialog::uploadProgress 246465 from 246465"
"FileSendDialog::uploadProgress 16384 from 246465"
"FileSendDialog::uploadProgress 32768 from 246465"
"FileSendDialog::uploadProgress 49152 from 246465"
"FileSendDialog::uploadProgress 65536 from 246465"
"FileSendDialog::uploadProgress 81920 from 246465"
"FileSendDialog::uploadProgress 98304 from 246465"
"FileSendDialog::uploadProgress 114688 from 246465"
"FileSendDialog::uploadProgress 131072 from 246465"
"FileSendDialog::uploadProgress 147456 from 246465"
"FileSendDialog::uploadProgress 163840 from 246465"
"FileSendDialog::uploadProgress 180224 from 246465"
"FileSendDialog::uploadProgress 196608 from 246465"
"FileSendDialog::uploadProgress 212992 from 246465"
"FileSendDialog::uploadProgress 229376 from 246465"
"FileSendDialog::uploadProgress 245760 from 246465"
"FileSendDialog::uploadProgress 246465 from 246465"
"FileSendDialog::uploadProgress 16384 from 246465"
"FileSendDialog::uploadProgress 32768 from 246465"
"FileSendDialog::uploadProgress 49152 from 246465"
"FileSendDialog::uploadProgress 65536 from 246465"
"FileSendDialog::uploadProgress 81920 from 246465"
"FileSendDialog::uploadProgress 98304 from 246465"
"FileSendDialog::uploadProgress 114688 from 246465"
"FileSendDialog::uploadProgress 131072 from 246465"
"FileSendDialog::uploadProgress 147456 from 246465"
"FileSendDialog::uploadProgress 163840 from 246465"
"FileSendDialog::uploadProgress 180224 from 246465"
"FileSendDialog::uploadProgress 196608 from 246465"
"FileSendDialog::uploadProgress 212992 from 246465"
"FileSendDialog::uploadProgress 229376 from 246465"
"FileSendDialog::uploadProgress 245760 from 246465"
"FileSendDialog::uploadProgress 246465 from 246465"
"Reply finished with code 2"
То есть, как видно, файл отправляется 3 раза и только потом вываливается finished с ошибкой. Сервер отвечает нормально, через тестовую прогу на пхп файл отправляется. В чем проблема?


Название: Re: [QNetworkAccessManager] post запрос отправляется 3 раза
Отправлено: Igore от Январь 24, 2012, 15:05
Сравни переданные данные от скрипта на php и Qt, зачем в хвосте + QByteArray (10 * 1024, ' ')?


Название: Re: [QNetworkAccessManager] post запрос отправляется 3 раза
Отправлено: Пантер от Январь 24, 2012, 15:11
Сравни переданные данные от скрипта на php и Qt, зачем в хвосте + QByteArray (10 * 1024, ' ')?
Сравнил - все одинаково и ответ сервака одинаковый. Зачем в хвосте пустота, я хз, но без нее такая же фигня.


Название: Re: [QNetworkAccessManager] post запрос отправляется 3 раза
Отправлено: Igore от Январь 24, 2012, 15:15
Стандартные вещи попробуй, clean + rebuild all, в коде ошибок не вижу  ???, а вот за само фомирование multipart/form-data не уверен, давно такое делал. Можешь еще выложить код php, запросы от Qt и php точно равны байт в байт?


Название: Re: [QNetworkAccessManager] post запрос отправляется 3 раза
Отправлено: Пантер от Январь 24, 2012, 15:20
Вот лог сервака на мою прогу:
Код:

[root@KS0000 ~]# logreceiver 4000 | grep stimp
stimp_13293: POST / HTTP/1.1
stimp_13293: Host: 192.168.2.193:8080
stimp_13293: Connection: keep-alive
stimp_13293: Keep-Alive: 300
stimp_13293: User-Agent: convertregui
stimp_13293: Content-Type: multipart/form-data; boundary=---------------------7c9758f23d
stimp_13293: Content-Length: 236203
stimp_13293: Accept-Encoding: gzip
stimp_13293: Accept-Language: ru-RU,en,*
stimp_13293: -----------------------7c9758f23d
stimp_13293: Content-Disposition: form-data; name="out_of_band"; filename="20120116141559.tar.log"
stimp_13293: Content-Type: application/octet-stream
stimp_13293:
stimp_13293:
stimp_13293: HTTP/1.0 200 OK
stimp_13293: Connection: keep-alive
stimp_13293: Content-Type: text/plain; charset=utf-8
stimp_13293:
stimp_13293:
stimp_13293:
stimp_13293: DONE!
stimp_13293:
stimp_13293: EXIT
stimp_13295:
stimp_13295: POST / HTTP/1.1
stimp_13295: Host: 192.168.2.193:8080
stimp_13295: Connection: keep-alive
stimp_13295: Keep-Alive: 300
stimp_13295: User-Agent: convertregui
stimp_13295: Content-Type: multipart/form-data; boundary=---------------------7c9758f23d
stimp_13295: Content-Length: 236203
stimp_13295: Accept-Encoding: gzip
stimp_13295: Accept-Language: ru-RU,en,*
stimp_13295: -----------------------7c9758f23d
stimp_13295: Content-Disposition: form-data; name="out_of_band"; filename="20120116141559.tar.log"
stimp_13295: Content-Type: application/octet-stream
stimp_13295:
stimp_13295:
stimp_13295: HTTP/1.0 200 OK
stimp_13295: Connection: keep-alive
stimp_13295: Content-Type: text/plain; charset=utf-8
stimp_13295:
stimp_13295:
stimp_13295:
stimp_13295: DONE!
stimp_13295:
stimp_13295: EXIT
stimp_13297:
stimp_13297: POST / HTTP/1.1
stimp_13297: Host: 192.168.2.193:8080
stimp_13297: Connection: keep-alive
stimp_13297: Keep-Alive: 300
stimp_13297: User-Agent: convertregui
stimp_13297: Content-Type: multipart/form-data; boundary=---------------------7c9758f23d
stimp_13297: Content-Length: 236203
stimp_13297: Accept-Encoding: gzip
stimp_13297: Accept-Language: ru-RU,en,*
stimp_13297: -----------------------7c9758f23d
stimp_13297: Content-Disposition: form-data; name="out_of_band"; filename="20120116141559.tar.log"
stimp_13297: Content-Type: application/octet-stream
stimp_13297:
stimp_13297:
stimp_13297: HTTP/1.0 200 OK
stimp_13297: Connection: keep-alive
stimp_13297: Content-Type: text/plain; charset=utf-8
stimp_13297:
stimp_13297:
stimp_13297:
stimp_13297: DONE!
stimp_13297:
stimp_13297: EXIT

А вот на пхп:
Код:
[root@KS0000 ~]# logreceiver 4000 | grep stimp
stimp_13291:
stimp_13291: POST / HTTP/1.0
stimp_13291: Host: 127.0.0.1
stimp_13291: Referer: 127.0.0.1
stimp_13291: Content-type: multipart/form-data; boundary=---------------------7c9758f23d
stimp_13291: Content-length: 236203
stimp_13291: -----------------------7c9758f23d
stimp_13291: Content-Disposition: form-data; name="out_of_band"; filename="20120116141559.tar.log"
stimp_13291: Content-Type: application/octet-stream
stimp_13291:
stimp_13291:
stimp_13291: HTTP/1.0 200 OK
stimp_13291: Connection: keep-alive
stimp_13291: Content-Type: text/plain; charset=utf-8
stimp_13291:
stimp_13291:
stimp_13291:
stimp_13291: DONE!
stimp_13291:
stimp_13291: EXIT

То есть сервак в обоих случаях одинаково отвечает.


Название: Re: [QNetworkAccessManager] post запрос отправляется 3 раза
Отправлено: SimpleSunny от Январь 24, 2012, 16:14
Попробуйте убрать
request.setRawHeader ("Connection", "keep-alive");
request.setRawHeader ("Keep-Alive", "300");
+ QByteArray (10 * 1024, ' ')

Запросы не совсем одинаковые
Разные версии HTTP используются
Сжатие применяется\не применяется
Присутствует Keep-Alive
И обращаетесь на разные порты


Название: Re: [QNetworkAccessManager] post запрос отправляется 3 раза
Отправлено: Пантер от Январь 24, 2012, 16:18
Попробуйте убрать
request.setRawHeader ("Connection", "keep-alive");
request.setRawHeader ("Keep-Alive", "300");
+ QByteArray (10 * 1024, ' ')

Запросы не совсем одинаковые
Разные версии HTTP используются
Сжатие применяется\не применяется
Присутствует Keep-Alive
Если убрать Keep-Alive, Кьют его сам добавляет. В логах уже без QByteArray (10 * 1024, ' ') - не помогло.


Название: Re: [QNetworkAccessManager] post запрос отправляется 3 раза
Отправлено: SimpleSunny от Январь 24, 2012, 16:30
А почему порты разные?


Название: Re: [QNetworkAccessManager] post запрос отправляется 3 раза
Отправлено: Пантер от Январь 24, 2012, 16:35
А почему порты разные?
Блин, надо же было не доглядеть. Огромное спасибо!


Название: Re: [НЕ РЕШЕНО] [QNetworkAccessManager] post запрос отправляется 3 раза
Отправлено: Пантер от Февраль 02, 2012, 16:15
Оказывается, не решено. Фишка вот в чем - на серваке на определенном порту висит прога, которая принимает файлы. Убрав порт из QUrl, я просто начал отправлять на стандартный (80) и его стал принимать аппач (а я обрадовался, что все заработало). Тот, кто пишет прогу, говорит, что он мне отдает ответ точно такой же, какой отдает аппач. Но вот QNetworkAccessManager'у что-то не нравится. Итак, что еще может быть? Может QNetworkAccessManager'а нужно как-то настроить?
Вот ответ проги:
Код:
HTTP/1.1 200 OK
Date: Thu, 2 Feb 2012 17:14:02 MSK
Server: Apache/2.2.16 (Debian)
Last-Modified: Thu, 2 Feb 2012 17:14:02 MSK
Accept-Ranges: bytes
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Length: 6
Content-Type: text/plain; charset=utf-8


DONE!


Название: Re: [НЕ РЕШЕНО] [QNetworkAccessManager] post запрос отправляется 3 раза
Отправлено: ufna от Февраль 02, 2012, 16:23
Пантер, ты бы сделал минимальный пример с ошибкой, и адрес куда тыркаться чтобы ее получить.


Название: Re: [НЕ РЕШЕНО] [QNetworkAccessManager] post запрос отправляется 3 раза
Отправлено: Пантер от Февраль 02, 2012, 16:23
ufna, еже ли бы оно было. Это внутренняя сетка.


Название: Re: [НЕ РЕШЕНО] [QNetworkAccessManager] post запрос отправляется 3 раза
Отправлено: thechicho от Февраль 12, 2012, 12:25
request.setRawHeader ("Connection", "close");
не?


Название: Re: [НЕ РЕШЕНО] [QNetworkAccessManager] post запрос отправляется 3 раза
Отправлено: SimpleSunny от Февраль 12, 2012, 13:32
А PHP как себя ведет, если отправлять не на апач, а на самописную прогу?


Название: Re: [НЕ РЕШЕНО] [QNetworkAccessManager] post запрос отправляется 3 раза
Отправлено: zenden от Февраль 12, 2012, 14:10
Честно говоря не в восторге от QNetworkAccessManager, профита от него никакого, а багов куча ( например, то как он работает с прокси просто ужасно).  Использую libcurl и горя не знаю.


Название: Re: [НЕ РЕШЕНО] [QNetworkAccessManager] post запрос отправляется 3 раза
Отправлено: thechicho от Февраль 12, 2012, 22:31
// Честно говоря не в восторге от QNetworkAccessManager, профита от него никакого, а багов куча ( например, то как он работает с прокси просто ужасно)
обоснуй на примерах. я в сотни потоков гоняю с проксями и без. нормально пашет.
// Использую libcurl и горя не знаю.
зачем в кьют использовать курл :-\


Название: Re: [НЕ РЕШЕНО] [QNetworkAccessManager] post запрос отправляется 3 раза
Отправлено: thechicho от Февраль 12, 2012, 22:33
правда сигнал финишед может не прийти (если тип прокси неверный указать у некоторых. и не только)
поэтому таймаут поставил.

http://pastebin.com/DMY55qv0


Название: Re: [НЕ РЕШЕНО] [QNetworkAccessManager] post запрос отправляется 3 раза
Отправлено: Пантер от Февраль 13, 2012, 09:43
Решил проблему написанием своего NetworkManager'а. Простенько и работает. :)


Название: Re: [НЕ РЕШЕНО] [QNetworkAccessManager] post запрос отправляется 3 раза
Отправлено: thechicho от Февраль 13, 2012, 19:15
дак выкладывай :)


Название: Re: [НЕ РЕШЕНО] [QNetworkAccessManager] post запрос отправляется 3 раза
Отправлено: Пантер от Февраль 14, 2012, 10:12
дак выкладывай :)
Да там все "абы хоть как-то работало". :)

networkmanager.h
Код
C++ (Qt)
#ifndef NETWORKMANAGER_H
#define NETWORKMANAGER_H
 
#include <QtCore/QObject>
 
#include <auto_ptr.h>
 
class QNetworkRequest;
 
namespace Network
{
class NetworkManagerPrivate;
class NetworkManager : public QObject
{
Q_OBJECT
 
public:
explicit NetworkManager (QObject *parent = 0);
~NetworkManager ();
 
void post (const QNetworkRequest &request, const QByteArray &data);
 
Q_SIGNALS:
void uploadProgress (qint64 bytesSent, qint64 bytesTotal);
void finished (bool result);
 
private:
Q_DISABLE_COPY (NetworkManager);
 
private:
typedef std::auto_ptr <NetworkManagerPrivate> Impl;
Impl impl_;
};
}
#endif // NETWORKMANAGER_H
 

networkmanager_p.h
Код
C++ (Qt)
#ifndef NETWORKMANAGER_P_H
#define NETWORKMANAGER_P_H
 
#include <QtCore/QObject>
 
#include "networkmanager.h"
 
class QTcpSocket;
class QTimer;
 
namespace Network
{
class NetworkManagerPrivate : public QObject
{
Q_OBJECT
 
public:
NetworkManagerPrivate ();
~NetworkManagerPrivate ();
 
void post (const QNetworkRequest &request, const QByteArray &data);
 
Q_SIGNALS:
void uploadProgress (qint64 bytesSent, qint64 bytesTotal);
void finished (bool result);
 
private Q_SLOTS:
void readyRead ();
void timeout ();
 
private:
Q_DISABLE_COPY (NetworkManagerPrivate);
 
private:
QTcpSocket *socket_;
QTimer *timer_;
};
}
#endif // NETWORKMANAGER_P_H
 

networkmanager.cpp
Код
C++ (Qt)
#include <QtCore/QDebug>
#include <QtCore/QStringList>
#include <QtCore/QTimer>
 
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QTcpSocket>
 
#include "networkmanager_p.h"
 
const uint defaultTimeout = 10 * 1000;//10 seconds
 
namespace Network
{
NetworkManagerPrivate::NetworkManagerPrivate ()
: QObject (0)
{
socket_ = new QTcpSocket (this);
connect (socket_, SIGNAL (readyRead ()), SLOT (readyRead ()));
 
timer_ = new QTimer (this);
timer_->setSingleShot (true);
connect (timer_, SIGNAL (timeout ()), SLOT (timeout ()));
}
 
NetworkManagerPrivate::~NetworkManagerPrivate ()
{
socket_->close ();
}
 
void NetworkManagerPrivate::readyRead ()
{
static const QRegExp doneRegexp ("^HTTP\\/([0-9]\\.[0-9]) ([0-9]+) (OK|ERROR)\r\n$");
 
while (socket_->canReadLine ()) {
const QString line = socket_->readLine ();
 
if (doneRegexp.exactMatch (line)) {
timer_->stop ();
emit finished (doneRegexp.cap (3) == QLatin1String ("OK"));
}
}
}
 
void NetworkManagerPrivate::post (const QNetworkRequest &request, const QByteArray &data)
{
emit uploadProgress (0, 100);
socket_->disconnectFromHost ();
 
const QUrl url = request.url ();
socket_->connectToHost (url.host (), url.port ());
 
if (socket_->waitForConnected (defaultTimeout)) {
emit uploadProgress (30, 100);
QStringList rawRequest;
rawRequest.push_back ("POST / HTTP/1.0");
 
foreach (const QString & header, request.rawHeaderList ()) {
rawRequest.push_back (header + ": " + request.rawHeader (header.toUtf8 ()));
}
 
rawRequest.push_back (QString ("Content-Length: %1").arg (data.size ()));
rawRequest.push_back ("\r\n");
 
socket_->write (rawRequest.join ("\r\n").toUtf8 ());
socket_->write (data);
timer_->start (defaultTimeout);
emit uploadProgress (100, 100);
} else {
QTimer::singleShot (0, this, SLOT (timeout ()));
}
 
}
 
void NetworkManagerPrivate::timeout ()
{
emit finished (false);
}
 
NetworkManager::NetworkManager (QObject *parent)
: QObject (parent), impl_ (new NetworkManagerPrivate)
{
connect (impl_.get (), SIGNAL (uploadProgress (qint64, qint64)),
SIGNAL (uploadProgress (qint64, qint64)));
connect (impl_.get (), SIGNAL (finished (bool)), SIGNAL (finished (bool)));
}
 
NetworkManager::~NetworkManager ()
{
 
}
 
void NetworkManager::post (const QNetworkRequest &request, const QByteArray &data)
{
impl_->post (request, data);
}
}