How to emit error for QLocalSocket - qt

I am implementing 'Local fortune server' example (from Qt 4.7.3) as a service on Windows.
What i want is that when someone paused the service, the local server should notify the error to the connected local socket (local fortune client). The error can be QLocalSocket::ServerNotFoundError.
Now, How to generate this error from server example. Please look at the following code where i want to generate this error.
void FortuneServer::incomingConnection(quintptr socketDescriptor)
{
if (disabled) {
**// here i want to emit QLocalSocket::ServerNotFoundError**
return;
}
QString fortune = fortunes.at(qrand() % fortunes.size());
FortuneThread *thread = new FortuneThread(socketDescriptor, fortune, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
void FortuneServer:: pause()
{
disabled = true;
}

If you want your server to notify your clients I think you should create and send your own message like :
QString fortune = "Server down";
But this will occure when your server has incoming message.
or you can shutdown the server whith the QTcpServer::close() method
void FortuneServer:: pause()
{
this.close();
}
your client app will lost its connection and you should be able to get the signal you want in it with this :
connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(displayError(QAbstractSocket::SocketError)));

You can't emit QLocalSocket::ServerNotFoundError, because it's not a signal. You should define your own signal and emit it instead (you can pass values in signals). You should also implement slot and connect signal to it. Read more about signals and slots.

Related

Qt - Crash when I use a tcp socket to write data if tcp server first closed and then reopened connection

I'm moving my application from Qt 4.7 to Qt 6.3. In Qt 4.7 all works fine. In Qt 6.3 I have some issues when tcp server closes connection, I establish again connection, and I try to write data.
This is the function I use to write to socket:
void NetworkFacility::Write(QTcpSocket& oTCPSocket, const QVariant& oV)
{
//Controls Socket is valid
if (oTCPSocket.state() == QAbstractSocket::ConnectedState)
{
QByteArray block; //ByteArray to serialiaze object
MyPacket oPacket; //Packet to send
//Set Size of QVariant object
oPacket.setPacketSize(getQVariantSize(oV));
//Set QVariant
oPacket.setTransport(oV);
//Create stream to write on ByteArray
QDataStream out(&block, QIODevice::WriteOnly);
//Sets version
out.setVersion(QDataStream::Qt_4_7);
//Serializes
out << oPacket;
//TX to socket
oTCPSocket.write(block);
}
}
I manage disconnection this way:
void MyClient::remoteNodeDisconnected()
{
m_pTCPSocket->flush();
m_pTCPSocket->close();
}
void MyClient::ManagesTCPError(QAbstractSocket::SocketError socketError)
{
//Clears last packets
m_pTCPSocket->flush();
}
This is connection portion of code after disconnection:
m_pTCPSocket->connectToHost(m_sIpAddress, m_iIpPort);
//Waits connection
if (m_pTCPSocket->waitForConnected(MSEC_WAIT_FOR_CONNECTION))
{
//Print connected and exit from while loop
break;
}
Finally this is the way in which I manage the remote server connecte:
void MyClient::remoteNodeConnected()
{
//Improve Network latency on this connection
m_pTCPSocket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
}
The issue is that on the first connection all works fine. If the server disconnects (i.e. I umplugg the server cable in my LAN or I shutdown and restarts the server application) and then connects again the call to:
oTCPSocket.write(block);
in Networkfacility::Write method generates a crash.
Why the write method generates a crash after reconnection?
I fixed the issue by removing completely th oTCPSocket instance.
void MyClient::remoteNodeDisconnected()
{
m_pTCPSocket->flush();
m_pTCPSocket->close();
m_pTCPSocket.deleteLater();
m_pTCPSocket = 0;
}

Sending a series of messages to a client from a QWebSocketServer in real-time

I have implemented a websocket server in a QCoreApplication. As soon as a connection is established with a client, I wish to send a series of messages to it immediately in real-time with a delay of 0.5 seconds between messages. However, the individual messages reach the client only after all the messages have been sent or right after sendMyMessages() method returns in the below implementation of my websocket server. If I have a huge number of messages to send, the client has to wait for a long time before getting all the messages in one go.
MyWebSocketServer.h
#ifndef MYWEBSOCKETSERVER_H
#define MYWEBSOCKETSERVER_H
#include <QtCore/QObject>
#include <QtCore/QList>
#include <QtCore/QByteArray>
QT_FORWARD_DECLARE_CLASS(QWebSocketServer)
QT_FORWARD_DECLARE_CLASS(QWebSocket)
class MyWebSocketServer : public QObject
{
Q_OBJECT
public:
explicit MyWebSocketServer(quint16 port,
bool debug = false,
QObject *parent = nullptr);
~MyWebSocketServer();
Q_SIGNALS:
void closed();
private Q_SLOTS:
void onNewConnection();
void socketDisconnected();
private:
void sendMyMessages(QWebSocket *client);
QWebSocketServer *m_pWebSocketServer;
QList<QWebSocket *> m_clients;
bool m_debug;
};
#endif // MYWEBSOCKETSERVER_H
MyWebSocketServer.cpp
#include "MyWebSocketServer.h"
#include <iostream>
#include <fstream>
#include <chrono>
#include <thread>
#include <QtWebSockets/qwebsocketserver.h>
#include <QtWebSockets/qwebsocket.h>
#include <QtCore/QDebug>
QT_USE_NAMESPACE
MyWebSocketServer::MyWebSocketServer(quint16 port,
bool debug,
QObject *parent)
: QObject(parent)
, m_pWebSocketServer(new QWebSocketServer(
QStringLiteral("My WebSocket Server"),
QWebSocketServer::NonSecureMode,
this))
, m_debug(debug)
{
connect(m_pWebSocketServer,
&QWebSocketServer::newConnection,
this,
&MyWebSocketServer::onNewConnection);
connect(m_pWebSocketServer,
&QWebSocketServer::closed,
this,
&MyWebSocketServer::closed);
m_pWebSocketServer->listen(QHostAddress::LocalHost, port);
}
MyWebSocketServer::~MyWebSocketServer()
{
m_pWebSocketServer->close();
qDeleteAll(m_clients.begin(), m_clients.end());
}
void MyWebSocketServer::onNewConnection()
{
QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection();
connect(pSocket,
&QWebSocket::disconnected,
this,
&MyWebSocketServer::socketDisconnected);
m_clients << pSocket;
sendMyMessages(pSocket);
}
void MyWebSocketServer::sendMyMessages(QWebSocket *client)
{
std::fstream jsonStringFileHandler;
jsonStringFileHandler.open("my-messages.txt", std::ios::in);
if (jsonStringFileHandler.is_open())
{
std::string message;
while(getline(jsonStringFileHandler, message))
{
// Individual messages don't go through immediately
// Only after this method returns, all the messages show up on the client's end
// Is it possible to send the individual messages immediately? (probably with a 0.5 second delay)
client->sendTextMessage(QString::fromUtf8(message.c_str()));
}
jsonStringFileHandler.close();
}
}
void MyWebSocketServer::socketDisconnected()
{
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
if (pClient)
{
m_clients.removeAll(pClient);
pClient->deleteLater();
}
}
Only after the sendMyMessages() returns, the client gets all the messages. It is not in real-time. I understand it would be possible to achieve what I am after using some asynchronous programming technique but I unable to figure out a way to set it up in my implementation of the websocket server.
Here is an implementation of the websocket server that worked for me in Python using the websockets and asyncio modules. However, I wish to implement the same logic in C++ using Qt.
import asyncio
import websockets
async def sendMyMessages(websocket, path):
with open("my-messages.txt") as fp:
lines = fp.readlines()
for line in lines:
await asyncio.sleep(0.5)
await websocket.send(line.strip())
start_server = websockets.serve(sendMyMessages, "127.0.0.1", 3000)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
One of the approaches I found uses QWebSocket::flush() immediately after a call to QWebSocket::sendTextMessage().
From the docs on QWebSocket::flush(),
This function writes as much as possible from the internal write buffer to the underlying network socket, without blocking. If any data was written, this function returns true; otherwise false is returned. Call this function if you need QWebSocket to start sending buffered data immediately. The number of bytes successfully written depends on the operating system. In most cases, you do not need to call this function, because QWebSocket will start sending data automatically once control goes back to the event loop.
However, I am not sure if this is the right approach as the doc indicates that the data may not be written to the underlying network socket reliably. I will be happy to know if there is a better technique out there!
client->sendTextMessage(QString::fromUtf8(message.c_str()));
client->flush();
std::this_thread::sleep_for(std::chrono::milliseconds(50));

How to send messages to connected clients from server in Qt

I know that how to send messages to the newly connected client whenever the QTcpServer newConnection is emitted. What I did is like this:
connect(serverConnection.tcpServer, &QTcpServer::newConnection, this, &ServerInterface::sendMessages);
void ServerInterface::sendMessages()
{
QByteArray messagesToClients;
QDataStream out(&messagesToClients, QIODevice::WriteOnly);
QTcpSocket *clientConnection = serverConnection.tcpServer->nextPendingConnection();
out << inputBox->toPlainText(); //get text from QTextEdit
clientConnection->write(messagesToClients);
}
But what I want to do is whenever the send messages button is clicked in the server, it will send messages to currently connected clients. The code I provide can only send only one new message to the newly connected client. I have no idea of how to achieve what I want to do, so can someone provide me a way to do that? I am kind of new to Qt networking.
Thanks.
Just store your connections in container. Like this:
in your ServerInterface h-file:
class ServerInterface {
// your stuff
public slots:
void onClientConnected();
void onClientDisconnected();
private:
QVector<QTcpSocket *> mClients;
};
in your ServerInterface cpp-file :
connect(serverConnection.tcpServer, SIGNAL(newConnection(), this, SLOT(onClientConnected());
void ServerInterface::onClientConnected() {
auto newClient = serverConnection.tcpServer->nextPendingConnection();
mClients->push_back( newClient );
connect(newClient, SIGNAL(disconnected()), this, SLOT(onClientDisconnected());
}
void ServerInterface::onClientDisconnected() {
if(auto client = dynamic_cast<QTcpSocket *>(sender()) {
mClients->removeAll(client);
}
void ServerInterface::sendMessages() {
out << inputBox->toPlainText();
for(auto &client : mClients) {
client->write(messagesToClients);
}
}

How to maintain a tcp socket in qt?

I have overloaded the incomingConnection function of QTcpServer at the server side with following code
void CtiServer::incomingConnection(int socketDescriptor)
{
qDebug() << QString("CtiServer thread id = %1, thread = %2").arg(QString::number((uint)QThread::currentThreadId(), 16)).arg(QString::number((qlonglong)QThread::currentThread(), 16));
ServerThread *thread = new ServerThread(socketDescriptor, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
Then in every thread i created a new QTcpSocket subclass object named ServerSocket,
void ServerThread::run()
{
qDebug() << QString("ServerThread thread id = %1, thread = %2").arg(QString::number((uint)QThread::currentThreadId(), 16)).arg(QString::number((qlonglong)QThread::currentThread(), 16));
serverSocket = new ServerSocket();
serverSocket->setSocketDescriptor(socketDescriptor);
connect(serverSocket, SIGNAL(readyRead()), serverSocket, SLOT(handleRequest()));
serverSocket->waitForDisconnected(-1);
}
The problem is whether serverSocket->waitForDisconnected(-1) is right or not.
I am trying to maintain the socket with this statement, util client send some message to notify the server socket that the connection should be shutdown, so that I could keep a long connection between server and client.
As a result, I could connect the disconnected signal and know when the client is down without bothering to set up some heart-beat protocol to detect whether a client is still alive or dead.
Or should I set up a heart-beat protocol and use code like following:
sock.disconnectFromHost();
sock.waitForDisconnected();
instead of sock.waitForDisconnected(-1).

waiting for a signal

I am working on an application which uploads the content of the file to server.
To upload the file to server I am using ‘QNetworkAccessManager’ class. Since it works as asynchronous way, I changed it to work as synchronous way by using QEventLoop.
Class FileTransfer
{
Public :
QNetworkAccessManager mNetworkManager;
Void Upload(QNetworkRequest request, QIODevice *data)
{
responce = mNetworkManager.put(request, data);
EventLoop.exec();
ReadResponce(responce);
}
Void Stop()
{
responce ->close();
}
}
In my sample application I have 2 windows. 1st to select the files and 2nd to show the progress.
When user click on upload button in the first window, the 2nd window will be displayed and then I create the FileTransfer object and start uploading.
While uploading the file if user closes the form then in the destructor of the window I call the stop of ‘FileTransfer’ after that I delete the ‘FileTransfer’ object.
But here the Upload() function is not yet completed so it will crash.
Please help me to:
How to wait in 'stop()' function until the Upload() function is completed
From what I can see from your code, you're executing a QEventLoop but you're not actually connecting its "quit" slot to any signal. Take the below as an example, login is a QHttp - and the code is taken from something different - but the principle applies.
/* Create the QEventLoop */
QEventLoop pause;
/* connect the QHttp.requestFinished() Signal to the QEventLoop.quit() Slot */
connect(&login, SIGNAL(requestFinished( int, bool )), &pause, SLOT(quit()));
/* The code that will run during the QEventLoop */
login.request(header,&logmein,&result);
/* Execute the QEventLoop - it will quit when the above finished due to the connect() */
pause.exec();
This could be applied to your code, if I'm not mistaken, like this...
/* connect the signal to the relevant slot */
connect(&mNetworkManager, SIGNAL(finished( QNetworkReply )), &EventLoop, SLOT(quit()));
/* Execute the code that will run during QEventLoop */
responce = mNetworkManager.put(request, data);
/* Execute the QEventLoop */
EventLoop.exec();
Apologies if I've mistaken your query! I'm only getting to grips with qt again after a break, but I believe this is what you mean! Good luck!
I think you need to add something like that in your upload function:
if (upf->openFile())
{
reply = manager->post(request, upf);
connect(reply, SIGNAL(uploadProgress(qint64,qint64)), this, SIGNAL(progress(qint64,qint64)));
connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
isInProgress = true;
emit started();
} else
{
emit finished(true, false, tr("Error: can't open file %1").arg(filename));
}
Here is the full text code: datacod-qt-tools
Hope it help.
Personally, I would recommend to not use any of these answers.
It would be sufficient to connect a countdown latch to the signal.
So you could write:
Latch latch( 1 );
QObject::connect( reply, SIGNAL(finished()),
&latch, SLOT(countDown()) );
latch.wait();
For this you would need a wrapper:
class Latch : public QObject {
Q_OBJECT
public:
Latch( uint count );
void wait();
public slots:
void countDown();
private:
gcl::countdown_latch _latch;
};

Resources