Why QTcpSocket doesn't write ? I need to flush it to make it send my data - c++

I read in the documentation that to send a packet with QTcpSocket I can just use the write method.
But when I do it, my server doesn't receive it. I need to call flush or waitForByteWritten to send it.
TCPClient::TCPClient(Client *babel , const std::string &hostname, unsigned short port, QObject *parent) : QObject(parent), client(babel), hostName(hostname), port(port), is_connected(false)
{
this->tcpSocket = new QTcpSocket(this);
connect(this->tcpSocket, SIGNAL(readyRead()),this, SLOT(readMessage()));
connect(this->tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)));
connect(this->tcpSocket, SIGNAL(connected()), this, SLOT(connectReady()));
connect(this->tcpSocket, SIGNAL(disconnected()), this, SLOT(disconnectedReady()));
}
TCPClient::~TCPClient()
{
}
bool TCPClient::initiateService()
{
this->tcpSocket->connectToHost(this->hostName.c_str(), this->port);
this->tcpSocket->waitForConnected(5000);
}
void TCPClient::connectReady()
{
this->is_connected = true;
}
void TCPClient::disconnectedReady()
{
}
bool TCPClient::sendBabelPacket(Protocol::BabelPacket &packet)
{
if(this->tcpSocket->state() == QAbstractSocket::ConnectedState && is_connected)
{
std::cout << "writing ... size : " << sizeof(Protocol::BabelPacket) + packet.dataLength<<std::endl;
this->tcpSocket->write((const char *)&packet, sizeof(Protocol::BabelPacket) + packet.dataLength);
//this->tcpSocket->flush();
return true;
}
else
{
std::cout << "socket close" << std::endl;
return false;
}
}
void TCPClient::shutDown()
{
this->tcpSocket->abort();
}
void TCPClient::displayError(QAbstractSocket::SocketError socketError)
{
}
void TCPClient::readMessage()
{
char buffer[sizeof(Protocol::BabelPacket)];
this->tcpSocket->read(buffer, sizeof(Protocol::BabelPacket));
}
When I call write, it returns the right amount of bytes.
I use this class in a GUI context, in the same thread.

QTcpSocket is a buffered device, so data is not written directly, but into internal buffer. Documentation states:
Note: TCP sockets cannot be opened in QIODevice::Unbuffered mode.
Because of it you should call flush or waitForBytesWritten to be sure something is transferred.
There is the difference between them. flush writes as much as possible from the internal write buffer to the underlying network socket, without blocking. waitForBytesWritten blocks until at least one byte has been written on the socket and the bytesWritten() signal has been emitted.

Related

asio async operations aren't processed

I am following ASIO's async_tcp_echo_server.cpp example to write a server.
My server logic looks like this (.cpp part):
1.Server startup:
bool Server::Start()
{
mServerThread = std::thread(&Server::ServerThreadFunc, this, std::ref(ios));
//ios is asio::io_service
}
2.Init acceptor and listen for incoming connection:
void Server::ServerThreadFunc(io_service& service)
{
tcp::endpoint endp{ address::from_string(LOCAL_HOST),MY_PORT };
mAcceptor = acceptor_ptr(new tcp::acceptor{ service,endp });
// Add a job to start accepting connections.
StartAccept(*mAcceptor);
// Process event loop.Hang here till service terminated
service.run();
std::cout << "Server thread exiting." << std::endl;
}
3.Accept a connection and start reading from the client:
void Server::StartAccept(tcp::acceptor& acceptor)
{
acceptor.async_accept([&](std::error_code err, tcp::socket socket)
{
if (!err)
{
std::make_shared<Connection>(std::move(socket))->StartRead(mCounter);
StartAccept(acceptor);
}
else
{
std::cerr << "Error:" << "Failed to accept new connection" << err.message() << std::endl;
return;
}
});
}
void Connection::StartRead(uint32_t frameIndex)
{
asio::async_read(mSocket, asio::buffer(&mHeader, sizeof(XHeader)), std::bind(&Connection::ReadHandler, shared_from_this(), std::placeholders::_1, std::placeholders::_2, frameIndex));
}
So the Connection instance finally triggers ReadHandler callback where I perform actual read and write:
void Connection::ReadHandler(const asio::error_code& error, size_t bytes_transfered, uint32_t frameIndex)
{
if (bytes_transfered == sizeof(XHeader))
{
uint32_t reply;
if (mHeader.code == 12345)
{
reply = (uint32_t)12121;
size_t len = asio::write(mSocket, asio::buffer(&reply, sizeof(uint32_t)));
}
else
{
reply = (uint32_t)0;
size_t len = asio::write(mSocket, asio::buffer(&reply, sizeof(uint32_t)));
this->mSocket.shutdown(tcp::socket::shutdown_both);
return;
}
}
while (mSocket.is_open())
{
XPacket packet;
packet.dataSize = rt->buff.size();
packet.data = rt->buff.data();
std::vector<asio::const_buffer> buffers;
buffers.push_back(asio::buffer(&packet.dataSize,sizeof(uint64_t)));
buffers.push_back(asio::buffer(packet.data, packet.dataSize));
auto self(shared_from_this());
asio::async_write(mSocket, buffers,
[this, self](const asio::error_code error, size_t bytes_transfered)
{
if (error)
{
ERROR(200, "Error sending packet");
ERROR(200, error.message().c_str());
}
}
);
}
}
Now, here is the problem. The server receives data from the client and sends ,using sync asio::write, fine. But when it comes to to asio::async_read or asio::async_write inside the while loop, the method's lambda callback never gets triggered, unless I put io_context().run_one(); immediately after that. I don't understand why I see this behaviour. I do call io_service.run() right after acceptor init, so it blocks there till the server exit. The only difference of my code from the asio example, as far as I can tell, is that I run my logic from a custom thread.
Your callback isn't returning, preventing the event loop from executing other handlers.
In general, if you want an asynchronous flow, you would chain callbacks e.g. callback checks is_open(), and if true calls async_write() with itself as the callback.
In either case, the callback returns.
This allows the event loop to run, calling your callback, and so on.
In short, you should make sure your asynchronous callbacks always return in a reasonable time frame.

readAll() from QSerialPort doesn't include the last response sent

I'm using Qt to control a serial device. If I send a command to my serial device, I do something like serial->write("command \r\n"). I made a push button which changes the text inside a plain text widget to the response of the serial port. To get the response of the serial port, I'm using serial->readAll(). The problem is it shows the 2nd to last response rather than the one I was expecting. Does Qt have some sort of buffer which is keeping hold of this response?
EDIT
I botched it by using recursion and compared the strings recieved
You might be calling readAll before the response is available. You should hook your code to the readyRead signal to be notified each time new chunk of data is ready to be read. Keep in mind that readyRead can be emitted with any number of bytes available to read - at a minimum, it'll be just one byte. You can't expect the data to be chunked/blocked in any particular way, since the serial port doesn't act as a message-based communication device. Your receiver code must be able to piece the data together from small chunks and act accordingly when it got all the data it needs.
For example, suppose that the device responses have a fixed, known length. You'd only want to react when a complete response has arrived. E.g.:
class Protocol : public QObject {
Q_OBJECT
QBasicTimer m_timer;
QPointer<QIODevice> m_port;
int m_responseLength = 0;
int m_read = 0;
void timerEvent(QTimerEvent * ev) override {
if (ev->timerId() != m_timer.timerId()) return;
m_timer.stop();
emit timedOut();
}
void onData() {
m_read += m_port->bytesAvailable();
if (m_read < m_responseLength)
return;
m_timer.stop();
emit gotResponse(m_port->read(m_responseLength));
m_read -= m_responseLength;
m_responseLength = 0;
}
public:
Q_SIGNAL void gotResponse(const QByteArray &);
Q_SIGNAL void timedOut();
Q_SLOT void sendCommand(const QByteArray & cmd, int responseLength, int cmdTimeout) {
m_responseLength = responseLength;
m_port->write(cmd);
m_timer.start(cmdTimeout, this);
}
explicit Protocol(QIODevice * port, QObject * parent = nullptr) :
QObject(parent), m_port(port) {
connect(m_port, &QIODevice::readyRead, this, &Protocol::onData);
}
};
...
Protocol protocol(0,0);
protocol.sendCommand({"foo"}, 10, 500);
QMetaObject::Connection cmd1;
cmd1 = QObject::connect(&protocol, &Protocol::gotResponse, [&]{
QObject::disconnect(cmd1);
qDebug() << "got response to foo";
});
QObject::connect(&protocol, &Protocol::timedOut, []{ qDebug() << "timed out :("; });

QSerialPort readyread() SIGNAL

I have a problem when receiving bytes from RS232 in QByteArray. I connected readyread() signal to call my serialport method and inside it I am reading bytes with readAll() to an QByteArray. Whenever data is available it rewrites QByteArray, but I want to receive it all, and then use data, but now I cannot because it is in parts. What to do?
Simply append to the array. You'll also need some criterion to determine when you've received all the data you wished. This can be, e.g. a given number of bytes:
class Communicator {
int expect;
QSerialPort port;
QByteArray reply;
void processReply() {
...
}
public:
Communicator() {
QObject::connect(&port, &QIODevice::readyRead, [this]{
reply += port.readAll();
if (expect && reply.size() >= expect) {
processReply();
reply.clear();
expect = 0;
}
});
...
};

Client Server program in qt

I am new in Qt, I want to write a simple client server program that client send a message to server and server get it and send it back to client.I wrote the server program but i have problem in client and I don't know how should I write it. could you please help me?
Here is my client code:
#include "myclient.h"
#include "QTcpsocket"
#include "QTcpServer"
#include "mainwindow.h"
Client::Client(QObject* parent): QObject(parent)
{
connect(&client, SIGNAL(connected()),this, SLOT(sendData()),Qt::DirectConnection);
}
void myclient::attemptConnection()
{
connect(QTcpSocket, SIGNAL(newConnection()), this, SLOT(connectionAccepted()));
if(QTcpSocket->listen("127.0.0.1",1234))
{
qDebug() << "Server listening";
}
else
{
qDebug() << "Couldn't listen to port" << server->serverPort() << ":" << server->errorString();
}
}
void myclient::connect()
{
QTcpSocket->connectToHost(LocalHost,1234,QIODevice::ReadWrite);
if(QTcpSocket->waitForConnected())
{
QString string = "Hello";
QByteArray array;
array.append(string);
qDebug()<<QTcpSocket->write(array);
}
else
{
qDebug() << "couldn't connect";
}
}
QTcpSocket socket;
void myclient::connectionAccepted()
{
qDebug()<<"Connected";
connect(socket, SIGNAL(readyRead()), this, SLOT(readSocket()));
}
void myclient::readSocket()
{
qDebug()<<socket->readBufferSize();
QByteArray = socket->readAll();
}
I think You Should take A look at the Forutne Client Example From Qt Docs, And base your code on it.
In your code you are using Both Blocking Functions from the waitFor*(), And Non-Blocking signals/slots (readyRead() signal), The Non-Blocking approach is Highly recommended (especially if the code is executed in the GUI thread).
Also I am not sure about your function attemptConnection, which uses newConnection() signal, new Connection is not even a member of QTcpSocket.

Qt C++ Console Server, Wait for socket connection & accept input at same time?

I am writing a server as a Qt console application. I have the server set up to wait for a socket connection, but I also need to allow a user to input commands into the server for managing it. Both are working independently. However, the problem I ran into is that when I'm in a while loop accepting and processing input commands, the server doesn't accept connections.
I have a Socket class, and in its constructor, I have:
connect(server,SIGNAL(newConnection()),this, SLOT(newConnection()));
Right under that in the constructor, I call a function that has a more in-depth version of this for getting commands from the user:
QTextStream qin(stdin, QIODevice::ReadOnly);
QString usrCmd;
while(usrCmd != "exit" && usrCmd != "EXIT") {
//Get command input and process here
}
Inside newConnection(), I just accept the next connection and then use the socket.
QTcpSocket *serverSocket = server->nextPendingConnection();
How can I make it so the socket can wait for connections and wait for user-inputed commands at the same time?
Problem with your code is because you are blocking event loop with your while loop. So, the solution to your problem is to read from stdin asynchronously. On Linux (and on Mac, I guess), you can use QSocketNotifier to notify when the data is arrived on stdin, and to read it manually), as per various internet sources.
As I am using Windows, I would suggest you to do it in this way (which should work on all platforms):
Open the thread for reading data from stdin
Once you get some data (perhaps line?) you can use Qt signal-slot mechanism to pass the data to main thread for processing without blocking the event loop.
So, this is the pseudocode. MainAppClass should your existing server class, just edit the constructor to create new thread, and add new slot for processing the data.
class Reader: public QThread
{
Q_OBJECT
public:
Reader(QObject * parent = 0 ): QThread(parent){}
void run(void)
{
forever{
std::string data;
std::getline (std::cin, data);
if(data == "exit")
{
emit exitServer();
return;
}
emit dataReady(QString::fromStdString(data));
}
}
signals:
void dataReady(QString data);
void exitServer();
};
class MainAppClass: public QObject
{
Q_OBJECT
public:
MainAppClass()
{
Reader * tr = new Reader(this);
connect(tr, SIGNAL(dataReady(QString)), this, SLOT(processData(QString)));
connect(tr, SIGNAL(exitServer()), this, SLOT(exitServer()));
tr->start();
}
public slots:
void processData(QString data)
{
std::cout << "Command: " << data.toStdString() << std::endl;
}
void exitServer()
{
std::cout << "Exiting..." << std::endl;
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainAppClass myapp; //your server
app.exec();
return 0;
}
Since I wrote simple guidelines how to use QTcpSocket, here is the brief
When you get client QTcpSocket, connect readyRead() signal to some slot, and read data from sender() object. You don't need to read anything in the constructor.
For reading you can use standard QIODevice functions.
Note: this is pseudo code, and you may need to change few things (check the state of the stream on reading, save pointer to sockets in some list, subscribe to disconnected() signal, call listen() in constructor, check if QTcpServer is listening, etc).
So, you need to have slot onReadyRead() in your class which will have the following code:
void Server::readyReadSlot()
{
QTcpSocket *client = (QTcpSocket*)sender(); // get socket which emited the signal
while(client->canReadLine()) // read all lines!
// If there is not any lines received (you may not always receive
// whole line as TCP is stream based protocol),
// you will not leave data in the buffer for later processing.
{
QString line = client->readLine();
processLine(line); // or emit new signal if you like
}
}
Inside newConnection() you need to connect readyRead() signal with your slot.
void Server::newConnection()
{
QTcpSocket *clientSocket = server->nextPendingConnection();
connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
}