QTcpSocket connecting results in UnknownSocketError with errorString "UnknownError" - qt

Problem
I am unable to get any further information regarding this error:
QAbstractSocket::UnknownSocketError
The QT QAbstractSocket::SocketError provides only a basic explanation that some error has occurred
An unidentified error occurred.
enum value = -1
Calling QTcpSocket::errorString() provides this:
"Unknown error"
There is one question regarding this here on SO but provides no real solution to solving the issue (and what was suggested I have done)
I have absoltely no idea how to further progress with this error, since each time my client attempts to connect (after calling connectToHost()) I get this error.
Code:
//Server
//...
if (tcpServer.listen(QHostAddress().AnyIPv4, 5000)) {
qDebug() << "tcpserver started on port : 5000";
}
else{
qDebug() << "tcpserver failed to start";
}
//...
I also went on to explicitly set the server ip to localhost and port 5000, but without success.
//Client
//...
tcp_con = new QTcpSocket(new QObject());
tcp_con->connectToHost("127.0.0.1", 5000);
switch (tcp_con->error()) {
//...
case QAbstractSocket::UnknownSocketError:
qDebug() << "tcp error UnknownSocketError closed : " << tcp_con->errorString();
return;
//...
}
Client debug output:
tcp error UnknownSocketError closed : "Unknown error"
Any advice?
p.s. I looked for some stacktrace/backtrace option, didn't find anything - if there is, please leave a comment

It is wrong to check an error immediately after the connectToHost(), because this is not a complete action, and the errorString() will always return "Unknown error". You have to call the QAbstractSocket::waitForConnected() method like this:
tcp_con->connectToHost("127.0.0.1", 5000);
if (tcp_con->waitForConnected(1000))
qDebug("Connected!");
Or you can don't call the waitForConnected() and asynchronously wait while the signal connected() will be emitted:
connect(tcp_con, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(onError(QAbstractSocket::SocketError)));
connect(tcp_con, SIGNAL(connected()),
this, SLOT(onConnect()));
//...
void MyClass::onConnect()
{
qDebug() << "Connected!";
}
void MyClass::onError(QAbstractSocket::SocketError)
{
QTcpSocket* sock = (QTcpSocket*)sender();
qDebug() << "Socket error:" << sock->errorString();
}

Related

Server Sent Events (SSE) with Qt

I already saw several libraries for Server Sent Events, unfortunately, not for Qt. I also looked at the specification of SSE (just plain HTTP) and it seems that implementing SSE in Qt would require to:
Use QNetworkAccessManager in streaming mode (download)
Accept the content type header of SSE: application/events-stream
Reconnect when the connection is lost or closed
Attach a slot to the QNAM when new bytes are received (check for data : {...})
I'm not sure if it's so "easy"? Did I miss something?
I created a small demo with Qt and Server Sent Events.
The demo connects to a given EventSource URL (first argument) and prints every event to the command line.
Qt supports SSE out of the box since SSE is pure HTTP with a reconnection layer on top of it.
Prepare the request: set the text/event-stream accept header, allow redirects, disable the cache.
QNetworkRequest Network::Manager::prepareRequest(const QUrl &url)
{
QNetworkRequest request(url);
request.setRawHeader(QByteArray("Accept"), QByteArray(ACCEPT_HEADER));
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); // Events shouldn't be cached
return request;
}
Connect the readyRead signal to a slot.
void Network::Manager::getResource(const QUrl &url)
{
qDebug() << "GET resource:" << url;
QNetworkRequest request = this->prepareRequest(url);
m_reply = this->QNAM()->get(request);
connect(m_reply, SIGNAL(readyRead()), this, SLOT(streamReceived()));
}
Every time a new event is received by the QNetworkAccessManager, you can read it using readAll. We reset the retries counter after every successful event.
void Network::Manager::streamReceived()
{
qDebug() << "Received event from stream";
qDebug() << QString(m_reply->readAll()).simplified().replace("data: ", "");
qDebug() << "-----------------------------------------------------";
m_retries = 0;
}
In case we lost the connection or the connection times out, the finished() signal is triggered of the QNetworkAccessManager. We try to reconnect to the event source (We connected this slot to the signal when we created our QNetworkAccessManager instance):
void Network::Manager::streamFinished(QNetworkReply *reply)
{
qDebug() << "Stream finished:" << reply->url();
qDebug() << "Reconnecting...";
if(m_retries < MAX_RETRIES) {
m_retries++;
this->getResource(reply->url());
}
else {
qCritical() << "Unable to reconnect, max retries reached";
}
}
You can find the demo here: https://github.com/DylanVanAssche/Qt-Server-Sent-Events-Demo

QIODevice::read (QSerialPort) : device not open

I'm new with Qt Creator and I'm trying to read data from a light sensor communicating by I2C. I made a class PortListener that should return data received on the console once called.
PortListener::PortListener(const QString &portName)
{
this->port = new QSerialPort();
port->setPortName(portName);
port->setBaudRate(QSerialPort::Baud9600);
port->setDataBits(QSerialPort::Data8);
port->setParity(QSerialPort::NoParity);
port->setStopBits(QSerialPort::OneStop);
port->setFlowControl(QSerialPort::NoFlowControl);
port->open(QIODevice::ReadWrite);
QByteArray readData = port->readAll();
qDebug() << "message:" << readData;
}
But the only message I have is:
QIODevice::read (QSerialPort): device not open
message: ""
I don't understand what that mean?
1.Open the serialport,then set the parameters.
PortListener::PortListener(const QString &portName)
{
this->port = new QSerialPort();
port->open(QIODevice::ReadWrite);
port->setPortName(portName);
port->setBaudRate(QSerialPort::Baud9600);
port->setDataBits(QSerialPort::Data8);
port->setParity(QSerialPort::NoParity);
port->setStopBits(QSerialPort::OneStop);
port->setFlowControl(QSerialPort::NoFlowControl);
}
2.Connect the readyRead signal to a slot, and the slot is like this.
void PortListener::readyReadSlot()
{
while (!port.atEnd()) {
QByteArray data = port.readAll();
}
}
This is much more like the QextSerialPort, the following is the code from my application.
void SpClient::start()
{
myComClient = new QextSerialPort(Setting::devCom);
if(myComClient->open(QIODevice::ReadWrite))
{
qDebug() << "open " << Setting::devCom << "as client success";
}
myComClient->setBaudRate(BAUD9600);
myComClient->setDataBits(DATA_8);
myComClient->setParity(PAR_NONE);
myComClient->setStopBits(STOP_1);
myComClient->setFlowControl(FLOW_OFF);
myComClient->setTimeout(50);
....
}
My guess is your code is failing to open the serial port, I have run into permissions issues under linux opening USB ports. You will just need to do a chmod to grant your $USER access mostly.

How set QTcpServer listening alone on port using Win7

I use a QTcpServer that should listen alone on port. Language is c++ with Qt 5.9. The application must run under Win and Linux using MingW. The listen method from QTcpServer uses standard parameter for socket options. For Win10, Linux these options are set default to single usage of the listening port so listening works fine. Unfortunatly opposite to that Win7 offers shared usage which i must avoid.
I figured out that the QAbstractSocket class let me create a socket with the BindFlag::DontShareAddress. I can forward the socketdescriptor to the QTcpServer. Then the method listen fails (isn't listening) by stating: QTcpServer::listen() called when already listening. I check the ports status by using netstat.
My code sample is below:
bool TcpServer::init(QString ipAddress, quint16 port, Command::RoutingProperty clientSocketKind, QString interfaceName)
{
if (mServerIsInit == true) // only 1 server instance
{
return false;
mServer = new (std::nothrow) QTcpServer();
if (mServer == nullptr)
{
return false;
}
mClientSocketKind = clientSocketKind;
mInterfaceName = interfaceName;
// tries to set socket properties to a non sharing port
QTcpSocket tsocket;
if (!tsocket.bind(QHostAddress(ipAddress), port, QAbstractSocket::BindFlag::DontShareAddress))
{
qDebug() << "Socket bind fails";
}
else
{
qDebug() << "Socket bind success";
}
sd = tsocket.socketDescriptor(); // valid socket descriptor
if (!mServer->setSocketDescriptor(sd))
{
qDebug() << "SocketDescriptor fails";
}
sd = mServer->socketDescriptor();
qDebug() << "Socketdescriptor Server " << sd;
//end tries to set socket properties to a non sharing port
if (mServer->listen(QHostAddress(ipAddress), port)) // fails with message ... is always listening
// if (mServer->mServer->isListening()) // is not listening tells netstat
{
qDebug() << "Server status for listening ok: " << mServer->isListening();
qDebug() << "Server listen on " << mServer->serverAddress() << ":" << mServer->serverPort();
connect(mServer, SIGNAL(newConnection()), this, SLOT(newConnection()));
connect(mServer, SIGNAL(acceptError(QAbstractSocket::SocketError)), this, SLOT(socketErr(QAbstractSocket::SocketError)));
mServerIsInit = true;
return true;
}
else
{
qDebug() << "Server status for listening fail" << mServer->isListening();
delete mServer;
mServer = nullptr;
return false;
}
}
Thanks for any idea how to set the socket options for a exclusive usage of the listening port.
Martin
As per the comment, you will probably need to call listen explicitly on the socket descriptor before calling QTcpServer::setSocketDescriptor.
The following code is untested but should give you some idea...
if (!tsocket.bind(QHostAddress(ipAddress), port, QAbstractSocket::BindFlag::DontShareAddress))
{
qDebug() << "Socket bind fails";
}
else
{
qDebug() << "Socket bind success";
}
sd = tsocket.socketDescriptor(); // valid socket descriptor
/*
* Now make an explicit call to `listen' so that the socket descriptor
* can be passed to QTcpSocket::setSocketDescriptoy.
*/
if (listen(sd, SOMAXCONN) == SOCKET_ERROR)
{
printf("Listen failed with error: %ld\n", WSAGetLastError());
closesocket(sd);
WSACleanup();
/*
* Handle error.
*/
}
if (!mServer->setSocketDescriptor(sd))
{
qDebug() << "SocketDescriptor fails";
}
As an aside, note that you need to be a bit more careful with error handling -- simply call qDebug and continuing will come back to bite you at some point.

Qt5 WebSockets test app not connecting to test service

I wanted to open a qt websocket to the test service in ws://echo.websocket.org but I got the error QAbstractSocket::RemoteHostClosedError
I am connecting the signal error(QAbstractSocket::SocketError socketError) to a slot in my code in order to read the error number then look for it in here
My code looks like this
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Controller w;
w.initializeWebSocket("ws://echo.websocket.org", true);
w.show();
return a.exec();
}
Controller::Controller(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
}
void Controller::initializeWebSocket(QString url, bool debug)
{
m_webSocketURL = url;
m_webSocketDebug = debug;
if(m_webSocketDebug)
std::cout << "WebSocket server: " << m_webSocketURL.toStdString() << std::endl;
QObject::connect(&m_webSocket, SIGNAL(connected()), this, SLOT(onConnected()));
QObject::connect(&m_webSocket, SIGNAL(disconnected()), this, SLOT(onDisconnected()));
QObject::connect(&m_webSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError)));
QObject::connect(&m_webSocket, SIGNAL(textMessageReceived(QString)), this, SLOT(onTextMessageReceived(QString)));
m_webSocket.open(QUrl(m_webSocketURL));
}
void Controller::onConnected()
{
if (m_webSocketDebug)
std::cout << "WebSocket connected" << std::endl;
m_webSocket.sendTextMessage(QStringLiteral("Rock it with HTML5 WebSocket"));
}
void Controller::onDisconnected()
{
if (m_webSocketDebug)
std::cout << "WebSocket disconnected" << std::endl;
}
void Controller::onError(QAbstractSocket::SocketError error)
{
std::cout << error << std::endl;
}
void Controller::onTextMessageReceived(QString message)
{
if (m_webSocketDebug)
std::cout << "Message received:" << message.toStdString() << std::endl;
m_webSocket.close();
}
Im new to websockets so I have no idea where could the problem be. Can anyone give advise?
Opening websocket at "ws://echo.websocket.org" works for me just fine.
These handlers are sufficient in my project:
connect(&webSocket, SIGNAL(connected()), this, SLOT(onConnected()));
connect(&webSocket, SIGNAL(disconnected()), this, SLOT(onDisconnected()));
connect(&webSocket, SIGNAL(textMessageReceived(const QString&)), this, SLOT(onTextMessageReceived(const QString&)));
I also just realized that I don't connect error() signal yet the program code is quite reliable for more than a year already and in case of disconnect there is a connection restore kick in. Maybe I should connect error() signal as well for infrequent strange cases.
The error QAbstractSocket::RemoteHostClosedError can be just a correct thing to get. Try to get the echo within reasonable time. The websocket farm we use in our project is holding the connection for up to 50 minutes so we do ping-pong between the client and the server to keep the connection live before this period expires.
// you can try that immediately after opening the web socket and also using some QTimer
m_webSocket.sendTextMessage("Pong!");
Try that and see the text reply as long as you are playing some public echo service.
Well, I verified your code and it seems to work fine. The error you give indicates a host related issue. It may be due to firewall, isp or other blocks/issues.
WebSocket server: ws://echo.websocket.org
WebSocket connected
Message received:Rock it with HTML5 WebSocket
WebSocket disconnected
I do like to point out that it's preferred to keep a pointer to a QWebSocket 'object'. It's very convenient to declare m_webSocket as QWebSocket *, and add m_webSocket = new QWebSocket(this). It's good practice to treat objects as objects. You don't want to accidentally try to 'copy' an QWebSocket directly. Also, due to the internals of Qt, you may eventually run into problems if this "Controller" object is destroyed while the QWebSocket is still attached to other objects (although I think Qt is prepared for it).

qt4 signal is not emitted

I have a QT4 application which wraps libssh2 in order to communicate with the embedded devices on the network. The following snippet is making me crazy for a while.
SSHClient ssh_client(host, 22);
try {
ssh_client.connect_to_host(USERNAME, PASSWORD);
ssh_client.receive_file(file_name, file_path);
} catch(const SSHException &excp) {
qDebug() << "test";
emit console(excp.what());
return;
}
I put breakpoints to qDebug() << "test"; and emit console(excp.what()); in debugger, however, they never get hit even though an SSHException is thrown. If i put a breakpoint to the return; statement, it stops with no problem.
The output is also strange. qDebug() << "test" does what it is supposed to do, but, emit console(excp.what()); is not emitting a signal. And when the control reaches to the return; statement, it returns, again with no problem.

Resources