Here is a small block of code above a read() statement in a synchronous TCP client that I've written.
std::cout << "available? " << socket->bytesAvailable() << std::endl;
socket->waitForReadyRead();
std::cout << "reading..." << std::endl;
bytesRead = socket->read(message + totalBytesRead, messageSize - totalBytesRead);
The following line:
socket->bytesAvailable()
returns 4, so there is obviously data available to be read. The problem that I'm having is that waitForReadyRead() is blocking until the default timeout of 30 seconds. Read() then proceeds to read 0 bytes on the following line.
So if there are bytes available to be read, why does waitForReadyRead() block
from QIODevice::waitForReadyRead documentation:
Blocks until new data is available for reading and the readyRead()
signal has been emitted, or until msecs milliseconds have passed. If
msecs is -1, this function will not time out.
Returns true if new data is available for reading; otherwise returns
false (if the operation timed out or if an error occurred).
The best why to handle network connection is to use signal/slots mechanism (the asynchronous why)
Related
I have a test program as below:
io_service io;
deadline_timer t1(io);
deadline_timer t2(io);
t1.expires_from_now(boost::posix_time::seconds(10));
t1.async_wait([](const boost::system::error_code &error) {
if (error == boost::asio::error::operation_aborted) {
cout << "timer1 canceled" << endl;
} else {
cout << "timer1 expired" << endl;
}
});
t2.expires_from_now(boost::posix_time::seconds(2));
t2.async_wait([&t1](const boost::system::error_code &error) {
if (error == boost::asio::error::operation_aborted) {
cout << "timer2 canceled" << endl;
} else {
t1.cancel();
for (int i = 0; i < 5000000; i++) {
cout << i << endl;
}
# usleep(1000000);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
cout << "timer2 expired" << endl;
}
});
io.run();
I was wondering when timer2 expires and cancels timer1, which one of "timer1 canceled" and "timer2 expired" will print as first?
The result is "timer2 expired". It makes sense as the single thread program will execution until some "block" happens.
But after inserting the line "sleep_for(1000ms)" (which should block the execution, trans the process to "Sleep"), the line "timer2 expired" still print before the line "timer1 canceled".
In my imagination, the boost:asio is something written around the "epoll" which can deal between "events" like incoming messages from network (the timer2 expires) and "blocks" like writing to disk (the sleep) in a single thread. But why didn't the line "timer1 canceled" reveal after "sleep_for"?
Question2: Assuming a program handling network request and Chrono jobs, in one thread.
void fun1(){
timer1.expire_from_now(3s);
timer1.async_wait([](const & error){
cout<<"timer1 expired";
heavy_job();
});
}
The fun1 expired, and executed cout<<"timer1 expired", but not executed. heavy_job yet. At this time, a request from network triggered fun2:
int wait_funcs= timer1.expire_from_now(3s);
if (wait_funcs == 0 ){
job2();
}else{
job3();
}
which of the following situation will happen?
heavy_job done -> job2:
which means func1 will not be interrupted by fun2, fun2 will run after fun1 completes(or blocks?)
job2 done -> heavy_job:
which means the wait_funcs check detected the unsafe behavior
Sorry about my demonstration, I am new to boost:asio and confused.
You can think of io_service as a producer-consumer queue: whenever an asyncronous operation gets completed (or aborted), its completion handler is pushed into the queue; while, on the other hand, io_service::run() fetches these handlers from the queue and invokes them.
Also note that as long as your program is single threaded (and does not use co-routines), all the completion handlers are always executed sequentially, one by one.
So, in you first example t2 timer expires first, and the completion handler gets invoked. The handler of t1 will not be fetched from the queue until the previous one completes - it doesn't matter how long it will take.
The same applies to your second example: the completion handler of timer1 is being run in the context of io_service::run, so the latter cannot fetch any subsequent handler until the previous one is done. So, if heavy_job() takes too long to complete, all other handlers will be stuck in the queue.
I have an application that uses ZeroMQ for various things and I want to also use it as a tcp-client for other external connections.
Currently if the external tcp-server sends data, the client receives 5 byte id, 0 bytes, 5 bytes, and then actual message.
How do I get ZeroMQ not to send this stuff?
#include <iostream>
#include <string>
#include <zmq.h>
#include <cstring>
#include <assert.h>
#include <chrono>
#include <thread>
int main()
{
void *mpSocketContext = zmq_ctx_new();
/* Create ZMQ_STREAM socket */
void *mpSerialSocket = zmq_socket(mpSocketContext, ZMQ_STREAM);
void *mpSocket = mpSerialSocket;
bool aeBlocking = true;
std::string asAddress = "127.0.0.1:1236";
asAddress = "tcp://" + asAddress;
std::cout << "tcSerialServerPort::tcSerialServerPort: connecting to " << asAddress << std::endl;
int rc = zmq_connect(mpSerialSocket, asAddress.c_str());
if (rc != 0)
std::cout << "ZMQ ERROR: zmq_connect " << zmq_strerror(zmq_errno()) << std::endl;
uint8_t id [256];
size_t id_size = 256;
rc = zmq_getsockopt (mpSerialSocket, ZMQ_IDENTITY, id, &id_size);
assert(rc == 0);
while(true)
{
zmq_msg_t msg;
zmq_msg_init(&msg);
size_t lnBytesReceived = 0;
std::string lsStr;
lnBytesReceived = zmq_recvmsg(mpSocket, &msg, aeBlocking ? 0 : ZMQ_DONTWAIT);
lsStr = std::string(static_cast<const char*>(zmq_msg_data(&msg)),
zmq_msg_size(&msg));
std::cout << "Received Bytes=" << lsStr.size() << " Data=" << lsStr << std::endl;
zmq_msg_close(&msg);
std::this_thread::sleep_for(std::chrono::seconds(1));
}
zmq_close(mpSerialSocket);
zmq_ctx_destroy(mpSocketContext);
return 0;
}
Step #1: Don't panic.
It is very easy - either stop using ZeroMQ, or start to design things compatible with the published ZeroMQ API documentation. Seeking a third way is still possible, but one may easily guess what such a fork-project will finish in.
Best let's start re-reading the design rules from the API:
"Why am I receiving extra info?" The ZeroMQ published API says:
Native pattern
The native pattern is used for communicating with TCP peers and allows asynchronous requests and replies in either direction.
ZMQ_STREAM
A socket of type ZMQ_STREAM is used to send and receive TCP data from a non-ØMQ peer, when using the tcp:// transport. A ZMQ_STREAM socket can act as client and/or server, sending and/or receiving TCP data asynchronously.
When receiving TCP data, a ZMQ_STREAM socket shall prepend a message part containing the identity of the originating peer to the message before passing it to the application. Messages received are fair-queued from among all connected peers.
When sending TCP data, a ZMQ_STREAM socket shall remove the first part of the message and use it to determine the identity of the peer the message shall be routed to, and unroutable messages shall cause an EHOSTUNREACH or EAGAIN error.
To open a connection to a server, use the zmq_connect call, and then fetch the socket identity using the ZMQ_IDENTITY zmq_getsockopt call.
To close a specific connection, send the identity frame followed by a zero-length message (see EXAMPLE section).
When a connection is made, a zero-length message will be received by the application. Similarly, when the peer disconnects (or the connection is lost), a zero-length message will be received by the application.
You must send one identity frame followed by one data frame. The ZMQ_SNDMORE flag is required for identity frames but is ignored on data frames.
The rest is obvious, follow the API documented behaviour in the user-code and all the ZeroMQ things work as charm.
I have to develop a C++ program for an embedded FriendlyARM-based processor system.
I use Qt Creator 3.0.0 (based on Qt 5.2.0) for desktop computer. My program should be able to read from serial port at Mini2440 FriendlyARM processor.
Before going to target system (embedded system), I tried to read and write from/to a serial port on my Laptop. My main problem is how to read from serial port. As you know, new computers and laptops don't have serial port so I try to simulate serial port programming using hand-made USB-to-serial adapter cable. When the USB serial cable is plugged in, it is recognized as "/dev/ttyUSB0" on Ubuntu. It seems to work well.
Please note, the other end of cable (the serial port) isn't connected to anything.
My first question is: Is it OK to configure cable like this, or I have to connect it to other device?
I try to wrote to /dev/ttyUSB0 each 10 seconds and read the data. I ended up the following code:
void MainWindow::refreshNotificationArea()
{
generateNotifAreaData(); // a typical random data-generator
QList<QSerialPortInfo> L = QSerialPortInfo::availablePorts();
for (auto e : L)
qDebug() << e.portName() << '\n'; // it prints 1 serial port: :ttyUSB0
// write to the port
QSerialPort notifAreaPort;
// 1. set properties
notifAreaPort.setBaudRate(QSerialPort::Baud9600);
notifAreaPort.setStopBits(QSerialPort::OneStop);
notifAreaPort.setParity(QSerialPort::NoParity);
notifAreaPort.setDataBits(QSerialPort::Data8);
notifAreaPort.setFlowControl(QSerialPort::NoFlowControl);
QObject::connect(¬ifAreaPort,SIGNAL(error(QSerialPort::SerialPortError)),
this, SLOT(errorReport(QSerialPort::SerialPortError)));
notifAreaPort.setPortName(serial_device.c_str());
// 2. open port
notifAreaPort.open(QIODevice::ReadWrite);
if (!notifAreaPort.isOpen())
qDebug() << "Open failed"; // open is OK, no error message printed
string s = convertNotifAreadData2Str();
qDebug() << "Generated data " << s.c_str(); // OK
int a = notifAreaPort.write(s.c_str()); // write done
qDebug() << "Write count" << a; // OK
// now read the info
QByteArray ba = notifAreaPort.readLine(3); // read failed
QSerialPort::SerialPortError err = notifAreaPort.error();
qDebug() << "Error code" << err;
qDebug() << "What? " << notifAreaPort.errorString();
qDebug() << "Read count " << ba.size(); // 0
notifAreaPort.close();
}
void MainWindow::errorReport(QSerialPort::SerialPortError error)
{
if(error!=0)
qDebug()<<"ERROR:"<<endl<<error; // nothing printed
}
Writing to serial port is OK. but Reading issues sometimes "No such file or directory"!
sometimes "File temporarily unavalable!
The strange thing is notifAreaPort.error() returns 0, and it means no error
occured!
Thoughts?
-- Saeed Amrollahi Boyouki
You cannot (well, SHOULD not) write then read from a QSerialPort in the same function.
There are two methods which I use for QSerialPort processing:
METHOD ONE
Create and open your QSerialPort object.
Set up a QTimer with a timeout of around 50 ms or so (depends on hardware).
Connect the readyRead() signal to a slot which basically just reads all data into your buffer (QByteArray is ideal for this). The slot stops the QTimer, reads all data available with readAll() and then restarts the QTimer and returns.
Connect the timeout signal of the QTimer to a function to process the read bytes of input.
The premise here is that eventually all data will have arrived and the QTimer will timeout, at which point you will have had all of your data in the buffer to process.
METHOD TWO
The slot which handles readyRead() signal can check all data in the buffer for some "marker" which denotes that some chunk of data has fully arrived. Many devices use 0x0D or 0x0d0x0A as the delmiter. Others use NULL 0x00 or some other byte.
Evaluate the buffer at each iteration of the readyRead() handler slot.
This example shows the second choice and it works well for small reads.
r_port = new QSerialPort(this);
r_port->setPortName("COM3");
r_port->setBaudRate(QSerialPort::Baud9600);
r_port->setDataBits(QSerialPort::Data8);
r_port->setParity(QSerialPort::NoParity);
r_port->setStopBits(QSerialPort::OneStop);
r_port->setFlowControl(QSerialPort::NoFlowControl);
if (r_port->open(QSerialPort::ReadWrite))
{
connect(r_port, &QSerialPort::readyRead, this, &MYPROG::on_readyRead);
connect(r_port, &QSerialPort::errorOccurred, this, &MYPROG::breakCaught);
}
else
{
QMessageBox::critical(this, "SERIAL PORT NOT CONNECTED", "Unable to connect to the radio.\n\nPlease check your connections\nand configuration and try again.");
return;
}
void MYPROG::on_readyRead()
{
// keep reading until we get a \r\n delimiter
rxBytes.append(r_port->readAll());
qDebug()<<"raw rxBtes"<<rxBytes;
if(!rxBytes.contains("\r\n"))
{
return;
}
int end = rxBytes.lastIndexOf("\r\n") + 2;
QStringList cmds = QString(rxBytes.mid(0, end)).split("\r\n", QString::SkipEmptyParts);
rxBytes = rxBytes.mid(end);
foreach(QString cmd, cmds){
qDebug()<<"serial read"<<cmd;
}
}
This allows the QSerialPort to be read when data arrives and then the program can return to the event loop in order to keep a GUI from becoming unresponsive. Typical serial reads are small and of short time duration so UI freezing rarely happens using these methods.
There are a couple of issues in your code, but I will highlight the most important of those:
You are setting the parameters before opening. This should happen after opening. That is how the API was sadly designed, but we are in the process of revamping it.
You should command line examples for reading that I added in 5.2? It seems that you do not know how to read and those would give you a simple example. In short: you are basically trying to read before the write potentially even finished.
„Hand-made USB to serial adapter“ - sounds interesting. Are you sure that this works correctly?. I think it’s a good idea to connect PIN 2(Rx) and 3(Tx), so you getting data. Now you can test your device with any other terminal software.
I use for serial ports always the readyRead() signal and I check before reading with port->bytesAvailable().
And I open my port with port->open(QIODevice::ReadWrite | QIODevice::Unbuffered).
I am trying to connect my application with a web service and here ,a user suggested to send custom headers back to my application.
I am using this code
void Coonnec::serviceRequestFinished(QNetworkReply *reply)
{
QByteArray bytes = reply->readAll();
if (reply->error() != QNetworkReply::NoError) {
qDebug() << "Reply error: " + reply->errorString();
}
else
{
qDebug() << "Uploaded: " + QDateTime::currentDateTime().toString();
qDebug() << reply->rawHeaderList();
}
reply->close();
bytes.clear();
reply->deleteLater();
}
from php i send this header
header('XAppRequest-Status: complete');
When running the application i can see that i get this header but i can't take the value of it cause
reply->rawHeader(bytes);
returns nothing.
How can i take the value 'complete'?
I suggest to connect a slot to the void QNetworkReply::metaDataChanged () signal of your reply.
The Qt doc says
This signal is emitted whenever the metadata in this reply changes.
metadata is any information that is not the content (data) itself,
including the network headers. In the majority of cases, the metadata
will be known fully by the time the first byte of data is received.
However, it is possible to receive updates of headers or other
metadata during the processing of the data.
I do use web-services/client with Qt and I noticed that some header's information are not available when I expected it to be ! I had to 'wait' for this signal to check the header content.
I'm developing an application that uses IPC between a local server and a client application. There is nothing particular to it, as it's structured like the Qt documentation and examples.
The problem is that the client sends packets frequently and connecting/disconnecting from the server local socket (named pipe on NT) is very slow. So what I'm trying to achieve is a "persistent" connection between the two applications.
The client application connects to the local server (QLocalServer) without any problem:
void IRtsClientImpl::ConnectToServer(const QString& name)
{
connect(_socket, SIGNAL(connected()), this, SIGNAL(connected()));
_blockSize = 0;
_socket->abort();
_socket->connectToServer(name, QIODevice::ReadWrite);
}
And sends requests also in the traditional Qt manner:
void IRtsClientImpl::SendRequest( quint8 cmd, const QVariant* const param_array,
unsigned int cParams )
{
// Send data through socket
QByteArray hdr(PROTO_BLK_HEADER_PROJ);
QByteArray dataBlock;
QDataStream out(&dataBlock, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_5);
quint8 command = cmd;
out << blocksize_t(0) // block size
<< hdr // header
<< quint32(PROTO_VERSION_PROJ) // protocol version
<< command // command
<< cParams; // number of valid parameters
for (unsigned int i = 0; i < cParams; ++i)
out << param_array[i];
// Write the current block size
out.device()->seek(0);
out << dataBlock.size() - sizeof(blocksize_t);
_socket->write(dataBlock);
}
No problem. But the trick resides on the readyRead() signal in the server-side. Here's the current implementation of the readyRead() handling slot:
void IRtsServerImpl::onReadyRead()
{
QDataStream in(_lsock);
in.setVersion(QDataStream::Qt_4_5);
if (_blocksize == 0)
{
qDebug("Bytes Available on socket: %d", _lsock->bytesAvailable());
if (_lsock->bytesAvailable() < sizeof(blocksize_t))
return;
in >> _blocksize;
}
// We need more data?
if (_lsock->bytesAvailable() < _blocksize)
return;
ReadRequest(in);
// Reset
_blocksize = 0;
}
Without setting _blocksize to zero I could not receive more data, only the first block group (I would expect an entire block to arrive without segmentation since this is through a pipe, but it does not, go figure). I expect that behavior, sure, since the _blocksize does not represent the current stream flow anymore. All right, resetting _blocksize does the trick, but I can't resend another packet from the client without getting an increasing array of bytes on the socket. What I want is to process the request in ReadRequest and receive the next data blocks without resorting to connecting/reconnecting the applications involved.
Maybe I should 'regulate' the rate of the incoming data?
Thank you very much.