use `QNetworkAccessManager` post request - qt

i use QNetworkAccessManager post request to a website:
void Spider::getProducts()
{
connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(getProducts(QNetworkReply*)));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
request.setUrl(QUrl("http://www.example.com/query"));
for(int i = 0; i < categories.size(); ++i)
{
if(categories[i].isCategory())
{
isSubCategory = false;
emit manager.finished(reply);
}
else
{
for(int page_number = 0; page_number < categories[i].getPageCount(); ++i)
{
isSubCategory = true;
QJsonObject json;
json.insert("NValue", categories[i].getNValue());
json.insert("NodeId", categories[i].getNodeId());
json.insert("StoreId", categories[i].getStoreId());
json.insert("StoreType", categories[i].getStoreType());
json.insert("PageNumber", ++page_number);
json.insert("SubCategoryId", categories[i].getSubCategoryId());
QJsonDocument doc;
doc.setObject(json);
QByteArray request_body = doc.toJson();
manager.post(request, request_body);
}
}
}
}
when i run this program, at beginning, this program run normally, after running for a while, it will stop: neither terminated nor continue to run. i can not figure out why it behavior like this? is there anything that needed to be noticed when use QNetworkAccess? or i am refused by that website? ...

You are using the same QNetworkAccessManager object in a loop multiple times. It is incorrect. For each separate post request you need a separate QNetworkAccessManager object if you want to send requests in parallel. Else if you only want to use a single instance then you need to serialize your post requests by sending next post request when the previous ends in the finished slot.
Updated: Try out this code, it uses single QNetworkAccessManager object, you will need to check for correct place of i++ as per your needs
connect(&manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(getProducts(QNetworkReply*))); // add this to constructor of your program
void Spider::getProducts()
{
static int i = 0;
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
request.setUrl(QUrl("http://www.example.com/query"));
while(categories[i].isCategory())
{
isSubCategory = false;
i++;
}
if(i == categories.size())
{
emit allPostRequestsDone();
return;
}
else
{
i++;
if(page_number < categories[i].getPageCount())
{
isSubCategory = true;
QJsonObject json;
json.insert("NValue", categories[i].getNValue());
json.insert("NodeId", categories[i].getNodeId());
json.insert("StoreId", categories[i].getStoreId());
json.insert("StoreType", categories[i].getStoreType());
json.insert("PageNumber", ++page_number);
json.insert("SubCategoryId", categories[i].getSubCategoryId());
QJsonDocument doc;
doc.setObject(json);
QByteArray request_body = doc.toJson();
manager.post(request, request_body);
}
}
}
}

Related

How to properly disconnect signal ready read from QNetworkreply

following issue abot my code. For unserstanding reason I connect to an event stream which publish every minute the actual status of a device under the url of : "urldevice"/event-stream. I connect a slot to the signal "readyread" and will disconnect. But still I am calling the disconnect function I recieve information in the cnnected slot.
Here is my code
QNetworkRequest request(_url + "events");
request.setRawHeader("Accept", "text/event-stream");
request.setHeader(QNetworkRequest::UserAgentHeader, "Plugin");
if (_token != "") {
request.setRawHeader("accept", "*/*");
QString token = "Bearer " + _token;
request.setRawHeader("Authorization", token.toUtf8());
}
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
request.setAttribute(QNetworkRequest::CacheLoadControlAttribute,
QNetworkRequest::AlwaysNetwork); // Events shouldn't be cached
_sseReply = _sseNetworkManager->get(request);
QObject::connect(_sseReply, &QNetworkReply::readyRead, this, &streamReceived);
void streamReceived() {
if (_sseReply->error() == QNetworkReply::NoError) {
qCDebug(m_logCategory) << "streamrecieved";
} else {
qCDebug(m_logCategory) << "disconnect";
}
}
void disconnect() {
if (_sseReply->isRunning()) {
_sseReply->abort();
_sseReply->close();
_sseNetworkManager->disconnect(_sseReply,&QNetworkReply::readyRead,this,&streamReceived);
_sseNetworkManager->disconnect();
_sseReply->disconnect();
qCDebug(m_logCategory) << "isrunnung";
}
_flagStandby = true;
QObject::disconnect(_sseReply, &QNetworkReply::readyRead, this, &streamReceived);
}
after caling disconnect() I see all the time
disconnect
in my log
How do I properly disconnect from the signal???

Is there any control property to fix video playback speed problem when using ffmpeg to decode in Qt platform?

I want to play local video file in Qt platform using ffmpeg to decode.Everything is OK except that play speed is as twice as normal.
The first thing I think about is that there must be a sampling frequency involved.But to be a new to ffmpeg,I don't know how to fix this problem.
Above is my code to read frame,is anyone can tell me what's wrong with the code ?
void VideoThread::run()
{
m_pInFmtCtx = avformat_alloc_context(); //ini struct
char path[] = "d:/test.mp4";
// open specific file
if(avformat_open_input(&m_pInFmtCtx, *path, NULL, NULL)){
{
qDebug()<<"get rtsp failed";
return;
}
else
{
qDebug()<<"get rtsp success";
}
if(avformat_find_stream_info(m_pInFmtCtx, NULL) < 0)
{
qDebug()<<"could not find stream information";
return;
}
int nVideoIndex = -1;
for(int i = 0; i < m_pInFmtCtx->nb_streams; i++)
{
if(m_pInFmtCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
nVideoIndex = i;
break;
}
}
if(nVideoIndex == -1)
{
qDebug()<<"could not find video stream";
return;
}
qDebug("---------------- File Information ---------------");
m_pCodecCtx = m_pInFmtCtx->streams[nVideoIndex]->codec;
m_pCodec = avcodec_find_decoder(m_pCodecCtx->codec_id);
if(!m_pCodec)
{
qDebug()<<"could not find codec";
return;
}
//start Decoder
if (avcodec_open2(m_pCodecCtx, m_pCodec, NULL) < 0) {
qDebug("Could not open codec.\n");
return;
}
//malloc space for stroring frame
m_pFrame = av_frame_alloc();
m_pFrameRGB = av_frame_alloc();
m_pOutBuf = (uint8_t*)av_malloc(avpicture_get_size(AV_PIX_FMT_RGB32, m_pCodecCtx->width, m_pCodecCtx->height));
avpicture_fill((AVPicture*)m_pFrameRGB, m_pOutBuf, AV_PIX_FMT_RGB32, m_pCodecCtx->width, m_pCodecCtx->height);
//for color switch,from YUV to RGB
struct SwsContext *pImgCtx = sws_getContext(m_pCodecCtx->width, m_pCodecCtx->height, m_pCodecCtx->pix_fmt,
m_pCodecCtx->width, m_pCodecCtx->height, AV_PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL);
int nSize = m_pCodecCtx->width * m_pCodecCtx->height;
m_pPacket = (AVPacket *)av_malloc(sizeof(AVPacket));
if(av_new_packet(m_pPacket, nSize) != 0)
{
qDebug()<<"new packet failed";
}
//isInterruptionRequested is a flag,determine whether the thread is over
// read each frame from specific video file
while (!isInterruptionRequested())
{
int nGotPic = 0;
if(av_read_frame(m_pInFmtCtx, m_pPacket) >= 0)
{
if(m_pPacket->stream_index == nVideoIndex)
{
//avcodec_decode_video2()transform from packet to frame
if(avcodec_decode_video2(m_pCodecCtx, m_pFrame, &nGotPic, m_pPacket) < 0)
{
qDebug()<<"decode failed";
return;
}
if(nGotPic)
{ // transform to RGB color
sws_scale(pImgCtx, (const uint8_t* const*)m_pFrame->data,
m_pFrame->linesize, 0, m_pCodecCtx->height, m_pFrameRGB->data,
m_pFrameRGB->linesize);
// save to QImage,for later use
QImage *pImage = new QImage((uchar*)m_pOutBuf, m_pCodecCtx->width, m_pCodecCtx->height, QImage::Format_RGB32);
}
}
}
av_free_packet(m_pPacket);
msleep(5);
}
exec();
}

Dart native extension : asynchronous but blocking?

After some try, it's that I can see :
The extension execution is asynchronous from dart but not C, which is blocking while the current method has not completed.
Dart_NativeFunction ResolveName(Dart_Handle name, int argc);
Dart_Handle HandleError(Dart_Handle handle);
void wrapped_method(Dart_Port dest_port_id, Dart_CObject* message) {
Dart_Port reply_port_id = message->value.as_array.values[0]->value.as_send_port;
printf("Before sleep\n");
sleep(5);
printf("Hello from c !\n");
Dart_CObject result;
result.type = Dart_CObject_kBool;
result.value.as_bool = true;
Dart_PostCObject(reply_port_id, &result);
}
DART_EXPORT Dart_Handle sample_extension_Init(Dart_Handle parent_library) {
if (Dart_IsError(parent_library)) { return parent_library; }
Dart_Handle result_code = Dart_SetNativeResolver(parent_library, ResolveName);
if (Dart_IsError(result_code)) return result_code;
return Dart_Null();
}
void sample_extension_ServicePort(Dart_NativeArguments arguments) {
Dart_EnterScope();
Dart_SetReturnValue(arguments, Dart_Null());
Dart_Port service_port = Dart_NewNativePort("sample_extension_ServicePort", wrapped_method, true);
if (service_port != ILLEGAL_PORT) {
Dart_Handle send_port = HandleError(Dart_NewSendPort(service_port));
Dart_SetReturnValue(arguments, send_port);
}
Dart_ExitScope();
}
struct FunctionLookup {
const char* name;
Dart_NativeFunction function;
};
FunctionLookup function_list[] = {
{"SampleExtension_ServicePort", sample_extension_ServicePort},
{NULL, NULL}};
Dart_NativeFunction ResolveName(Dart_Handle name, int argc) {
if (!Dart_IsString(name)) return NULL;
Dart_NativeFunction result = NULL;
Dart_EnterScope();
const char* cname;
HandleError(Dart_StringToCString(name, &cname));
for (int i=0; function_list[i].name != NULL; ++i) {
if (strcmp(function_list[i].name, cname) == 0) {
result = function_list[i].function;
break;
}
}
Dart_ExitScope();
return result;
}
Dart_Handle HandleError(Dart_Handle handle) {
if (Dart_IsError(handle)) Dart_PropagateError(handle);
return handle;
}
When I execute 3 times a method calling the service port :
Hello from Dart
Hello from Dart
Before sleep
Hello from Dart
Hello from c !
Before sleep
Hello from c !
Before sleep
Hello from c !
Until every "Hello from c!", its sleep 5 seconds.
There is a way to be also asynchronous in the C side ?
I have seen :
DART_EXPORT Dart_Port Dart_NewNativePort(const char* name,
Dart_NativeMessageHandler handler,
bool handle_concurrently);
Great ! But ...
/* TODO(turnidge): Currently handle_concurrently is ignored. */
Is there a issue about that ? (I want to vote for it to follow solutions)
While the issue is not fixed, what is the best solution ?
Running code in a C fork ?

Setting default TWAIN data source without using API UI menu

Using the twaindotnet library in C#, I'm wondering if there's a way to set the default datasource using the library.
As a feeble attempt, I've tried adding a SetDefault method to the DataSource class of twaindonet, like this
public static void SetDefault(Identity applicationId, IWindowsMessageHook messageHook, DataSource newDataSource)
{
var defaultSourceId = newDataSource.SourceId;
// Attempt to get information about the system default source
var result = Twain32Native.DsmIdentity(
applicationId,
IntPtr.Zero,
DataGroup.Control,
DataArgumentType.Identity,
Message.Set,
defaultSourceId);
if (result != TwainResult.Success)
{
var status = DataSourceManager.GetConditionCode(applicationId, null);
throw new TwainException("Error getting information about the default source: " + result, result, status);
}
}
which is called from the DataSourceManage class like this
public void SelectSource(DataSource dataSource)
{
DataSource.Dispose();
DataSource.SetDefault(ApplicationId, _messageHook, dataSource);
}
But when I try to use SetDefault, Twain32Native.DsmIdentity always results in Failure being returned.
I basically copied from SetDefault the setDefaultDataSource method from TWAIN sample Data Source and Application
pTW_IDENTITY TwainApp::setDefaultDataSource(unsigned int _index)
{
if(m_DSMState < 3)
{
cout << "You need to open the DSM first." << endl;
return NULL;
}
else if(m_DSMState > 3)
{
PrintCMDMessage("A source has already been opened, please close it first\n");
return NULL;
}
if(_index >= 0 && _index < m_DataSources.size())
{
m_pDataSource = &(m_DataSources[_index]);
// set the specific data source
TW_UINT16 twrc;
twrc = _DSM_Entry(
&m_MyInfo,
0,
DG_CONTROL,
DAT_IDENTITY,
MSG_SET,
(TW_MEMREF) m_pDataSource);
switch (twrc)
{
case TWRC_SUCCESS:
break;
case TWRC_FAILURE:
printError(0, "Failed to get the data source info!");
break;
}
}
else
{
return NULL;
}
return m_pDataSource;
}
Any help would be greatly appreciated.
The possible cause is that the version of your TWAIN DSM is too low. Only DSM 2.0 or above supports setting default TWAIN data source.

Qt QNetworkAccessManager and multiple QNetworkReply

I have two get QNetworkRequest.
I want to handle finished signals from different methods.
For example this is code in
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
GetUserData();
connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(GetUserDataCompleted(QNetworkReply*)));
GetMessages();
connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(GetMessagesCompleted(QNetworkReply*)));
}
This my one method
I have tried replay->deleteLater(); but same result
Please advice me something useful
void MainWindow::GetUserDataCompleted(QNetworkReply *replay)
{
if(replay->error() == QNetworkReply::NoError)
{
QString getData = replay->readAll();
QMessageBox msg;
if(getData == "1")
{
msg.setText("User Is not Exits");
}
else
{
QDomDocument doc;
if(doc.setContent(getData))
{
QDomElement domElem = doc.documentElement();
QDomNode n = domElem.firstChild();
while(!n.isNull()) {
QDomElement e = n.toElement(); // try to convert the node to an element.
if(!e.isNull()) {
msg.setText(e.namedItem("Image").childNodes().at(0).nodeValue());
msg.exec();
}
n = n.nextSibling();
}
}
replay->deleteLater();
}
}
}
You can create a RequestSender class whose role is looking after requests.
Each RequestSender object will handle one unique request. While creating the QNetworkRequest that will be sent, the RequestSender will "tag" its own request with the originatingObject attribute. This attribute indicates which object sent the request. When a RequestSender object receives a reply, it will look if it is the sender of the request via the originatingObject attribute. For further informations about originatingObject, you can refer to the documentation here : http://qt-project.org/doc/qt-4.8/qnetworkrequest.html#originatingObject
Below is an example of what you can do.
requestsender.hpp :
class RequestSender {
public:
RequestSender();
~RequestSender();
void createRequest(/* Request parameters */);
public slots:
void endRequest(QNetworkReply* replay);
};
requestsender.cpp :
RequestSender::RequestSender() {
connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(endRequest(QNetworkReply*)));
}
RequestSender::~RequestSender() {
disconnect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(endRequest(QNetworkReply*)));
}
void RequestSender::createRequest(/* Request parameters */) {
QNetworkRequest * myRequest = 0;
// Build myRequest with the request parameters
myRequest->setOriginatingObject(this);
nam->get(*myRequest);
}
void RequestSender::endRequest(QNetworkReply* replay) {
if (replay->request().originatingObject() != this) {
// That's not the request sent by the object -> stop the method here !
return;
}
// Treatments on replay
}
Every operation you do with your QNetworkAccessManager will return a QNetworkReply. This has also has an signal finished(). Maybe you can connect this signal to your different slots.

Resources