How to properly disconnect signal ready read from QNetworkreply - qt

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???

Related

async grpc server handling multiple types of request

Is there a better example on how to implement multiple async requests.
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc ListSayHello1 (HelloRequest1) returns (stream HelloReply1) {}
rpc ListSayHello2 (HelloRequest2) returns (stream HelloReply2) {}
}
// The request message containing the user's name.
message HelloRequest1 {
string name = 1;
}
message HelloRequest2 {
string name = 1;
}
// The response message containing the greetings
message HelloReply1 {
string message = 1;
}
message HelloReply2 {
string message = 1;
}
I am using below async pattern to handle SayHello1, but now I want to add support for SayHello2. What should be the approach?
new CallData(&service_, cq_.get(), *this);
void* tag; // uniquely identifies a request.
bool ok;
while (true) {
// Block waiting to read the next event from the completion queue. The
// event is uniquely identified by its tag, which in this case is the
// memory address of a CallData instance.
// The return value of Next should always be checked. This return value
// tells us whether there is any kind of event or cq_ is shutting down.
GPR_ASSERT(cq_->Next(&tag, &ok));
GPR_ASSERT(ok);
static_cast<CallData*>(tag)->Proceed();
}
In CallData, I doing this
void CallData::Proceed()
{
if (status_ == CREATE) {
status_ = PROCESS;
service_->RequestListSayHello1(&ctx_, &request_, &writer_, cq_, cq_,
this);
}
...
}
It is not necessary to create extra completion queues. We just need to know how to handle what the completion queue returns. We can solve this by making a common base class, that is able to do the necessary functions:
class CallDataBase
{
protected:
virtual void WaitForRequest() = 0;
virtual void HandleRequest() = 0;
public:
virtual void Proceed() = 0;
CallDataBase() {}
};
Each specialization of CallDataBase know how to Proceed, WaitForRequest and HandleRequest. Some of this is common for all requests, so it is convenient to use a templatized class:
template < class RequestType, class ReplyType>
class CallDataT : CallDataBase
{
protected:
enum CallStatus { CREATE, PROCESS, FINISH };
CallStatus status_;
Greeter::AsyncService* service_;
ServerCompletionQueue* completionQueue_;
RequestType request_;
ReplyType reply_;
ServerAsyncResponseWriter<ReplyType> responder_;
ServerContext serverContext_;
// When we handle a request of this type, we need to tell
// the completion queue to wait for new requests of the same type.
virtual void AddNextToCompletionQueue() = 0;
public:
CallDataT(Greeter::AsyncService* service, ServerCompletionQueue* completionQueue) :
status_(CREATE),
service_(service),
completionQueue_(completionQueue),
responder_(&serverContext_)
{
}
public:
virtual void Proceed() override
{
if (status_ == CREATE)
{
status_ = PROCESS;
WaitForRequest();
}
else if (status_ == PROCESS)
{
AddNextToCompletionQueue();
HandleRequest();
status_ = FINISH;
responder_.Finish(reply_, Status::OK, this);
}
else
{
// We're done! Self-destruct!
if (status_ != FINISH)
{
// Log some error message
}
delete this;
}
}
};
And finally, the actual implementation of the message types:
class CallDataHello : CallDataT<HelloRequest, HelloReply>
{
public:
CallDataHello(Greeter::AsyncService* service, ServerCompletionQueue* completionQueue) : CallDataT(service, completionQueue)
{
Proceed();
}
protected:
virtual void AddNextToCompletionQueue() override
{
new CallDataHello(service_, completionQueue_);
}
virtual void WaitForRequest() override
{
service_->RequestSayHello(&serverContext_, &request_, &responder_, completionQueue_, completionQueue_, this);
}
virtual void HandleRequest() override
{
reply_.set_message(std::string("Hello ") + request_.name());
}
};
class CallDataHelloAgain : CallDataT<HelloAgainRequest, HelloAgainReply>
{
public:
CallDataHelloAgain(Greeter::AsyncService* service, ServerCompletionQueue* completionQueue) : CallDataT(service, completionQueue)
{
Proceed();
}
protected:
virtual void AddNextToCompletionQueue() override
{
new CallDataHelloAgain(service_, completionQueue_);
}
virtual void WaitForRequest() override
{
service_->RequestSayHelloAgain(&serverContext_, &request_, &responder_, completionQueue_, completionQueue_, this);
}
virtual void HandleRequest() override
{
reply_.set_message(std::string("Hello again ") + request_.name());
}
};
Finally, in the GRPC server implementation, we can then handle the different requests in a unified way:
void HandleRpcs()
{
new CallDataHello(&service_, completionQueue.get());
new CallDataHelloAgain(engine_, &service_, completionQueue.get());
void* tag;
bool ok;
while (true) {
bool ret = completionQueue->Next(&tag, &ok);
if (ok == false || ret == false)
{
return;
}
static_cast<CallDataBase*>(tag)->Proceed();
}
}
This works because all the CallData we add to completionQueue, is of baseclass CallDataBase, so we can safely call Proceed() on them. This approach makes it relatively easy to add new requests. All the requests are handled by the same completion queue. However, all the requests will be handled serially, so if you are after more parallel processing, I think you have to make more than one completion queue.
I was able to figure this out.
For every protobuf function, I had to create separate completion queue.

I want my multihopOscilloscope to send data through radio and Serial port as well

I am trying to modify the multihop Oscilloscope program so that the sink node is able to send data both to UART and radio medium as well. As far as researched, I found out that the same hardware is used for sending packets via UART and radio too.
In this case, how do I modify my code so that I can send data to UART or radio based on a condition I receive. Here in the sample prorgram, I send data via radio on every 10 packets received.
The receive module for my sink node is:
event message_t* Receive.receive(message_t* msg, void *payload, uint8_t len) {
oscilloscope_t* in = (oscilloscope_t*)payload;
counter++;
am_addr_t rec = call AMPacket.source(msg);
oscilloscope_t* out;
counter++;
call Leds.led0On();
if (uartbusy == FALSE) {
out = (oscilloscope_t*)call SerialSend.getPayload(&uartbuf, sizeof(oscilloscope_t));
if (len != sizeof(oscilloscope_t) || out == NULL) {
return msg;
}
else {
memcpy(out, in, sizeof(oscilloscope_t));
}
uartlen = sizeof(oscilloscope_t);
post uartSendTask();
} else {
message_t *newmsg = call UARTMessagePool.get();
if (newmsg == NULL) {
report_problem();
return msg;
}
//Serial port busy, so enqueue.
out = (oscilloscope_t*)call SerialSend.getPayload(newmsg, sizeof(oscilloscope_t));
if (out == NULL) {
return msg;
}
memcpy(out, in, sizeof(oscilloscope_t));
if (call UARTQueue.enqueue(newmsg) != SUCCESS) {
call UARTMessagePool.put(newmsg);
fatal_problem();
return msg;
}
}
if(counter % 10 == 0){
oscilloscope_t* btrpkt = (oscilloscope_t*)(call Packet.getPayload(&pkt, sizeof(oscilloscope_t)));
call Leds.led1On();
if (call AMSend.send(rec, &pkt, sizeof(oscilloscope_t)) == SUCCESS) {
call Leds.led0On();
sendbusy = TRUE;
}
}
return msg;
}
Once the data sends back to the node from where it received the packet , it is unable to process it through UART again. Could anyone help me how could I solve my problem?
According to the question and comments:
You must instantiate AMSenderC with the same id as for the receiver. In this case, AM_OSCILLOSCOPE if you want a message to be processed by the same code. Or another id plus a new implementation of the Receive interface.
You missed putting payload into btrpkt.
You must check for sendbusy - it is a bug if you try to use the radio stack when it is busy.

Android BLE: writing >20 bytes characteristics missing the last byte array

I have been implementing the module to send the bytes in chunks, 20 bytes each onto the MCU device via BLE. When it comes to writing the bytes more than 60 bytes and so on, the last chunk of the bytes ( usually less than 20 bytes) is often missed. Hence, the MCU device cannot get the checksum and write the value. I have modified the call back to Thread.sleep(200) to change it but it sometimes works on writing 61 bytes or sometimes not. Would you please tell me are there any synchronous method to write the bytes in chunks ? The below is my working :
#Override
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
try {
Thread.sleep(300);
if (status != BluetoothGatt.GATT_SUCCESS) {
disconnect();
return;
}
if(status == BluetoothGatt.GATT_SUCCESS) {
System.out.println("ok");
broadcastUpdate(ACTION_DATA_READ, mReadCharacteristic, status);
}
else {
System.out.println("fail");
broadcastUpdate(ACTION_DATA_WRITE, characteristic, status);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public synchronized boolean writeCharacteristicData(BluetoothGattCharacteristic characteristic ,
byte [] byteResult ) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
return false;
}
boolean status = false;
characteristic.setValue(byteResult);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
status = mBluetoothGatt.writeCharacteristic(characteristic);
return status;
}
private void sendCommandData(final byte [] commandByte) {
// TODO Auto-generated method stub
if(commandByte.length > 20 ){
final List<byte[]> bytestobeSent = splitInChunks(commandByte);
for(int i = 0 ; i < bytestobeSent.size() ; i ++){
for(int k = 0 ; k < bytestobeSent.get(i).length ; k++){
System.out.println("LumChar bytes : "+ bytestobeSent.get(i)[k] );
}
BluetoothGattService LumService = mBluetoothGatt.getService(A_SERVICE);
if (LumService == null) { return; }
BluetoothGattCharacteristic LumChar = LumService.getCharacteristic(AW_CHARACTERISTIC);
if (LumChar == null) { System.out.println("LumChar"); return; }
//Thread.sleep(500);
writeCharacteristicData(LumChar , bytestobeSent.get(i));
}
}else{
....
You need to wait for the onCharacteristicWrite() callback to be invoked before sending the next write. The typical solution is to make a job queue and pop a job off the queue for each callback you get to onCharacteristicWrite(), onCharacteristicRead(), etc.
In other words, you can't do it in a for loop unfortunately, unless you want to set up some kind of lock that waits for the callback before going on to the next iteration. In my experience a job queue is a cleaner general-purpose solution though.

use `QNetworkAccessManager` post request

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);
}
}
}
}

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