I get the error:
QIODevice::write (QTcpSocket): device not open.
After trying , I think problem is passing parameter server->nextPendingConnection() into object. Can someone has idea how to do it correctly?
My understanding is that object for socketClient is not initialised properly.
I'm using Ubuntu with Qt.
I am implementing server using Qt. The server part has two classes based on QTcpServer and QTcpSocket.
say Server and SocketClient.
I am creating object of SocketClient in server and for testing purpose I opened telnet session and wants to see that server write "hello" on terminal. But somehow its not working. Can someone please advice me where I am making mistake.
Server::Server(QObject *parent) : QObject(parent)
{
server_obj = new QTcpServer( this );
}
void Server::startServer()
{
connect( server_obj, SIGNAL( newConnection() ), this, SLOT( incomingConnection() ) );
if( !server_obj->listen( QHostAddress::Any, 9999) )
{
qDebug() << " Server failed to get started";
}
else
{
qDebug() << " Server started"; // this is successful
}
}
void Server::incomingConnection()
{
socketforClient = new SockClient( server_obj->nextPendingConnection() );// has a doubt on nextPendingconection??
//only for testing remove it
socketforClient->writeToClient();
}
Class for Client
* Description: Its a constructor.I have changed default constructor to add QTcpSocket* object in parameter.I used this constructor in void Server::incomingConnection()
*/
SockClient::SockClient(QObject *parent,QTcpSocket* socket ) : QObject(parent)
{
socketClient = new QTcpSocket( socket );
qDebug() << " we are in constructor of 1st sockclient ";
}
// this is for testing purpose only
void SockClient::writeToClient()
{
socketClient->write(" hello world\r\n");
socketClient->flush();
socketClient->waitForBytesWritten(3000);
}
//header file of SockClient
class SockClient : public QObject
{
Q_OBJECT
public:
explicit SockClient( QObject *parent, QTcpSocket* socket= 0 ); // I have created
void writeToClient(); // This is for testing purpose
~SockClient();
signals:
private slots:
void readClient();
private:
void sendResponsetoMops();
QTcpSocket *socketClient;
quint16 nextBlockSize;
public slots:
};
You use:
socketClient = new QTcpSocket( socket );
Try to use following code instead:
socketClient = socket;
And use
socketforClient = new SockClient(this, server->nextPendingConnection() );
instead of
socketforClient = new SockClient( server->nextPendingConnection() );
Related
See EDIT1 at the end of the question for a possible solution - It would be great if somebody could comment on my interpretation, so that I can understand better what's happening
I'm writing a simple TCP client, based on QTcpSocket and managed by a QStateMachine (connect to server -> transmit data -> if disconnected for any reason, reconnect to server).
I noticed that if the connection is shut down on the server side (client is notified with RemoteHostClosedError), after reconnection the QTcpSocket write() method succeeds but no data is transmitted on the wire - nothing is received by the server, and the bytesWritten() signal on the client side does not fire up.
I found in the documentation for error() signal (https://doc.qt.io/qt-5/qabstractsocket.html#error) that
When this signal is emitted, the socket may not be ready for a reconnect attempt. In that case,
attempts to reconnect should be done from the event loop".
I think I'm already ok with that, as the reconnection happens in one of the QStateMachine states, and QStateMachine should have its own event loop according to the QT docs.
Below some simplified code to reproduce the issue (sorry, not so minimal but I could not find a simpler way to show the problem):
testclient.h
#ifndef TESTCLIENT_H
#define TESTCLIENT_H
#include <QObject>
#include <QTcpSocket>
#include <QDebug>
#include <QStateMachine>
class TestClient : public QObject
{
Q_OBJECT
public:
explicit TestClient(QObject *parent = nullptr);
public slots:
void start();
signals:
// FSM events
void fsmEvtConnected();
void fsmEvtError();
private slots:
void onSocketConnected(); // Notify connection to TCP server
void onSocketDisconnected(); // Notify disconnection from TCP server
void onSocketBytesWritten(qint64 bytes); // Notify number of bytes written to TCP server
void onSocketError(QAbstractSocket::SocketError err);
// FSM state enter/exit actions
void onfsmConnectEntered();
void onfsmTransmitEntered();
void onfsmTransmitExited();
private:
// Member variables
QTcpSocket* m_socket; // TCP socket used for communications to server
QStateMachine* m_clientFsm; // FSM defining general client behaviour
private:
void createClientFsm(); // Create client FSM
};
#endif // TESTCLIENT_H
testclient.cpp
#include "testclient.h"
#include <QState>
#include <QThread> // Sleep
//-----------------------------------------------------------------------------
// PUBLIC METHODS
//-----------------------------------------------------------------------------
TestClient::TestClient(QObject *parent) : QObject(parent)
{
m_socket = new QTcpSocket(this);
connect(m_socket, SIGNAL(connected()),this, SLOT(onSocketConnected()));
connect(m_socket, SIGNAL(disconnected()),this, SLOT(onSocketDisconnected()));
connect(m_socket, SIGNAL(bytesWritten(qint64)),this, SLOT(onSocketBytesWritten(qint64)));
connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onSocketError(QAbstractSocket::SocketError)));
}
void TestClient::start()
{
createClientFsm();
m_clientFsm->start();
}
//-----------------------------------------------------------------------------
// TCP CONNECTION MANAGEMENT SLOTS
//-----------------------------------------------------------------------------
void TestClient::onSocketConnected()
{
qDebug() << "connected...";
emit fsmEvtConnected();
}
void TestClient::onSocketDisconnected()
{
qDebug() << "disconnected...";
emit fsmEvtError();
}
void TestClient::onSocketBytesWritten(qint64 bytes)
{
qDebug() << bytes << " bytes written...";
}
void TestClient::onSocketError(QAbstractSocket::SocketError err)
{
qDebug() << "socket error " << err;
}
//-----------------------------------------------------------------------------
// FSM MANAGEMENT
//-----------------------------------------------------------------------------
void TestClient::createClientFsm()
{
m_clientFsm = new QStateMachine(this);
// Create states
QState* sConnect = new QState();
QState* sTransmit = new QState();
// Add transitions between states
sConnect->addTransition(this, SIGNAL(fsmEvtConnected()), sTransmit);
sTransmit->addTransition(this, SIGNAL(fsmEvtError()), sConnect);
// Add entry actions to states
connect(sConnect, SIGNAL(entered()), this, SLOT(onfsmConnectEntered()));
connect(sTransmit, SIGNAL(entered()), this, SLOT(onfsmTransmitEntered()));
// Add exit actions to states
connect(sTransmit, SIGNAL(exited()), this, SLOT(onfsmTransmitExited()));
// Create state machine
m_clientFsm->addState(sConnect);
m_clientFsm->addState(sTransmit);
m_clientFsm->setInitialState(sConnect);
}
void TestClient::onfsmConnectEntered()
{
qDebug() << "connecting...";
m_socket->connectToHost("localhost", 11000);
// Wait for connection result
if(!m_socket->waitForConnected(10000))
{
qDebug() << "Error: " << m_socket->errorString();
emit fsmEvtError();
}
}
void TestClient::onfsmTransmitEntered()
{
qDebug() << "sending data...";
m_socket->write("TEST MESSAGE");
}
void TestClient::onfsmTransmitExited()
{
qDebug() << "waiting before reconnection attempt...";
QThread::sleep(2);
}
main.cpp
#include <QCoreApplication>
#include "testclient.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
TestClient client(&a);
client.start();
return a.exec();
}
To test, you can just launch netcat (nc -l -p 11000) , then close the nc process after receiving TEST MESSAGE and finally relaunch it again. The second time, TEST MESSAGE is not received, and we don't have the onSocketBytesWritten() printout, see below:
connecting...
connected...
sending data...
12 bytes written... <<<<<<<<<< Correct transmission, event fires up
socket error QAbstractSocket::RemoteHostClosedError
disconnected...
waiting before reconnection attempt...
connecting...
connected...
sending data... <<<<<<<<<< No transmission, event does not fire up, no socket errors!
EDIT1: I found out that if I create the QTcpSocket on connection and destroy it on disconnection, the problem does not happen. Is this the expected/proper way to use sockets?
Wouldn't it be possible instead to create the socket just once and just connect/disconnect? Maybe it is just a matter of flushing or cleaning up in a specific manner, but I could not find it so far.
Here are the modifications that make the code above work on server-side disconnection:
Move socket creation from class constructor to onfsmConnectEntered() - handler for entry in the "Connect" QState:
void TestClient::onfsmConnectEntered()
{
m_socket = new QTcpSocket(this);
connect(m_socket, SIGNAL(connected()),this, SLOT(onSocketConnected()));
connect(m_socket, SIGNAL(disconnected()),this, SLOT(onSocketDisconnected()));
connect(m_socket, SIGNAL(bytesWritten(qint64)),this, SLOT(onSocketBytesWritten(qint64)));
connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onSocketError(QAbstractSocket::SocketError)));
qDebug() << "connecting...";
m_socket->connectToHost("localhost", 11000);
// The rest of the method is the same
}
Delete the socket on disconnection, so that it is deallocated and will be created again on reconnection:
void TestClient::onSocketDisconnected()
{
qDebug() << "disconnected...";
m_socket->deleteLater();
m_socket = nullptr;
emit fsmEvtError();
}
Do not use waitForX methods as they block the event loop and prevent them from using that resource as the signals do not do their job correctly or the QStateMachine.
Considering the above, the solution is:
void TestClient::onfsmConnectEntered()
{
m_socket->connectToHost("localhost", 11000);
}
But even so your code has errors since it does not consider other cases such as:
If when you start the client the server is not running, your application will try to connect the error will be launched and nothing else.
If the server fails for a longer time than the 10000 ms timeout set to waitForConnected(), the same will happen as in the previous case.
Then the idea is to try to connect until you are sure of the connection and that can be done through a QTimer with an appropriate period.
testclient.h
#ifndef TESTCLIENT_H
#define TESTCLIENT_H
#include <QObject>
class QTcpSocket;
class QStateMachine;
class QTimer;
#include <QAbstractSocket>
class TestClient : public QObject
{
Q_OBJECT
public:
explicit TestClient(QObject *parent = nullptr);
public slots:
void start();
signals:
// FSM events
void fsmEvtConnected();
void fsmEvtError();
private slots:
void onSocketConnected(); // Notify connection to TCP server
void onSocketDisconnected(); // Notify disconnection from TCP server
void onSocketBytesWritten(qint64 bytes); // Notify number of bytes written to TCP server
void onSocketError(QAbstractSocket::SocketError err);
// FSM state enter/exit actions
void onfsmConnectEntered();
void onfsmTransmitEntered();
private:
// Member variables
QTcpSocket* m_socket; // TCP socket used for communications to server
QStateMachine* m_clientFsm; // FSM defining general client behaviour
QTimer* m_timer;
private:
void createClientFsm(); // Create client FSM
void tryConnect();
};
#endif // TESTCLIENT_H
testclient.cpp
#include "testclient.h"
#include <QState>
#include <QStateMachine>
#include <QTcpSocket>
#include <QThread> // Sleep
#include <QTimer>
//-----------------------------------------------------------------------------
// PUBLIC METHODS
//-----------------------------------------------------------------------------
TestClient::TestClient(QObject *parent) : QObject(parent)
{
m_socket = new QTcpSocket(this);
m_timer = new QTimer(this);
m_timer->setInterval(100);
connect(m_timer, &QTimer::timeout, this, &TestClient::tryConnect);
connect(m_socket, &QAbstractSocket::connected,this, &TestClient::onSocketConnected);
connect(m_socket, &QAbstractSocket::disconnected,this, &TestClient::onSocketDisconnected);
connect(m_socket, &QIODevice::bytesWritten,this, &TestClient::onSocketBytesWritten);
connect(m_socket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error), this, &TestClient::onSocketError);
}
void TestClient::start()
{
createClientFsm();
m_clientFsm->start();
}
//-----------------------------------------------------------------------------
// TCP CONNECTION MANAGEMENT SLOTS
//-----------------------------------------------------------------------------
void TestClient::onSocketConnected()
{
m_timer->stop();
qDebug() << "connected...";
emit fsmEvtConnected();
}
void TestClient::onSocketDisconnected()
{
qDebug() << "disconnected...";
emit fsmEvtError();
}
void TestClient::onSocketBytesWritten(qint64 bytes)
{
qDebug() << bytes << " bytes written...";
}
void TestClient::onSocketError(QAbstractSocket::SocketError err)
{
qDebug() << "socket error " << err;
}
//-----------------------------------------------------------------------------
// FSM MANAGEMENT
//-----------------------------------------------------------------------------
void TestClient::createClientFsm()
{
m_clientFsm = new QStateMachine(this);
// Create states
QState* sConnect = new QState();
QState* sTransmit = new QState();
// Add transitions between states
sConnect->addTransition(this, SIGNAL(fsmEvtConnected()), sTransmit);
sTransmit->addTransition(this, SIGNAL(fsmEvtError()), sConnect);
// Add entry actions to states
connect(sConnect, &QAbstractState::entered, this, &TestClient::onfsmConnectEntered);
connect(sTransmit, &QAbstractState::entered, this, &TestClient::onfsmTransmitEntered);
// Create state machine
m_clientFsm->addState(sConnect);
m_clientFsm->addState(sTransmit);
m_clientFsm->setInitialState(sConnect);
}
void TestClient::tryConnect(){
m_socket->connectToHost("localhost", 11000);
}
void TestClient::onfsmConnectEntered()
{
m_timer->start();
}
void TestClient::onfsmTransmitEntered()
{
qDebug() << "sending data...";
m_socket->write("TEST MESSAGE");
}
I am implementing client side of TCP-Ip server based on Qt but the program crashes when I closed connection and start again by hitting connect button.
Overview of project. I have Qwidget ( main application) with 2 lineEdit for user to input port number and server Ip address.
It also has 2 button that connect to server and disconnect. On hitting connect button , it will call constructor of client socket and call connectToHost.
Testing: Tried testing on same computer with server running on port 6000 and ip address 127.0.0.1.
Problem: When I launch Client application.And input port number and address and hit connect button it connects successfully. And I can write to server successfully. then I click disconnect button and it disconnects successfully but after that if I connect again by clicking connect button it crashes. I know problem is with tcpSocket but have no idea how to fix it.
clientAgent( QWidget appilciation ).h
namespace Ui {
class ClientAgent;
}
class ClientAgent : public QWidget
{
Q_OBJECT
public:
explicit ClientAgent(QWidget *parent = 0);
~ClientAgent();
private:
Ui::ClientAgent *ui;
ClientForTest *tcpSockForTest;
// Qwidget declartion
below
....
private slots:
void startClient();
void stopClient();
public slots:
void getCliReqTextChanged();
};
ClientAgent.cpp
ClientAgent::ClientAgent( QWidget *parent ) :
QWidget(parent),
ui( new Ui::ClientAgent )
{
// Widget declartion and initilisation
// Layout design etc
//define signals and slots for Client
// signals and slots
connect( btnStartClient, SIGNAL( clicked() ), this, SLOT( startClient() ) );
connect( btnStopClient, SIGNAL( clicked() ), this, SLOT( stopClient() ) );
// for write
connect( lEditCliReq, SIGNAL( textChanged(const QString& ) ), this, SLOT( getCliReqTextChanged() ) );
ui->setupUi( this );
}
ClientAgent::~ClientAgent()
{
delete ui;
}
void ClientAgent::startClient()
{
qDebug() << " we are in strt Clinet";
qDebug() << " connecting ";
// get server address and port number from GUI
QString testAddr = lEditAddr->text();
QString testPort = lEditPrt->text();
tcpSockForTest = new ClientForTest( testAddr, testPort.toInt(), this );
if( tcpSockForTest->connectToServer() == true )
{
lblCliStatus->setText(" connected ....");
}
else
{
lblCliStatus->setText(" failed to connect....");
}
}
void ClientAgent::stopClient()
{
qDebug() << " disconnecting ";
tcpSockForTest->disconnectToServer();
delete tcpSockForTest;
}
ClientForTest.h
class ClientForTest : public QObject
{
Q_OBJECT
public:
ClientForTest( QString hostAddr, quint16 portNum, QObject *parent );
bool connectToServer();
void disconnectToServer();
QString getStoreMsgFrmCliReq( ) const;
void writeToTest(const QString& stripCmd );
void executeSignals();
~ClientForTest();
signals:
void sigSendData();
public slots:
void connectedToTest();
void connectionClosedByServer();
void error();
private:
QTcpSocket *sockFortest;
QString hostName;
quint16 portNumber;
quint16 nextBlockSize;
QString storeLineEditMsg;// store message from lineEditCliReq;
};
ClientForTest.cpp
ClientForTest::ClientForTest( QString hostAddr, quint16 portNum, QObject *parent ) :
hostName( hostAddr ),
portNumber( portNum ),
QObject( parent )
{
connect( sockFortest, SIGNAL( connected() ), this, SLOT( connectedToTest() ) );
connect( sockFortest, SIGNAL( disconnected() ), this, SLOT( connectionClosedByServer() ) );
connect( sockFortest, SIGNAL( error( QAbstractSocket::SocketError ) ), this, SLOT( error() ) );
storeLineEditMsg = "";
}
void ClientForTest::executeSignals()
{
// actually I need toplace itin constructor will do later on
connect( this, SIGNAL( sigSendData() ), this, SLOT( connectedToTest() ) );
}
ClientForTest::~ClientForTest()
{
sockFortest->close();
delete sockFortest;
}
bool ClientForTest::connectToServer()
{
sockFortest = new QTcpSocket( this->parent() ); // COULD be Probelm here but how to fix it?
sockFortest->connectToHost( hostName, portNumber );
nextBlockSize = 0;
executeSignals();
return sockFortest->waitForConnected(1000);
}
void ClientForTest::disconnectToServer()
{
sockFortest->close();
//sockFortest.close();
qDebug() << "in disconnect for Test ";
emit updateLabelinParent( updateStatusDis );
}
void ClientForTest::connectionClosedByServer()
{
qDebug() << "connection closed by server ";
if( nextBlockSize != 0xFFFF )
{
disconnectToServer();
}
}
void ClientForTest::error()
{
qDebug() << "in error ";
disconnectToServer();
}
void ClientForTest::writeToTest( const QString& stripCmd )
{
storeLineEditMsg = stripCmd;
if( sockFortest->state() == QTcpSocket::UnconnectedState )
{
sockFortest->close();
delete sockFortest;
sockFortest = new QTcpSocket( this->parent() );
if( connectToServer() == true )
{
qDebug() << " YEEEE CONNECTED AGAIN finally ";
}
}
if( sockFortest->state() == QTcpSocket::ConnectedState )
{
qDebug() << " YEEEE CONNECTED";
sigSendData();
}
}
void ClientForTest::connectedToTest( )
{
QByteArray block;
QDataStream out( &block, QIODevice::WriteOnly );
out.setVersion( QDataStream::Qt_4_3 );
QString stripCmd = getStoreMsgFrmCliReq(); // received info for some other function I havnt shown that func here
out << quint16( 0 ) << stripCmd;
out.device()->seek( 0 );
out << quint16( block.size() - sizeof( quint16 ) );
qDebug()<<" yeeeee connected state...";
sockFortest->write( block );
//reset storeLineEditMessage
storeLineEditMsg.clear();
}
A few things, that could all together be responsible for your crash:
you connect the signals inside the ClientForTest constructor, but the socket itself is created later. That won't work. Move the line sockFortest = new QTcpSocket(this); to the constructor, before connecting
Same line, use this instead of this->parent()
And finally: There are multiple places you create/delete the socket. Don't do it. Create the socket inside the constructor with this as parent, and that's it. In your connectToServer, establish the connection, and in disconnectToServer, close it using disconnectFromHost. Same goes for the startClient and stopClient. Create the object once and just use the connect/disconnect functions, no deleting.
If code is required, I can add some.
Since it was requested, here is some more explanation:
Of course you can use parent, but in your case, the ClientForTest is an QObject, too. If you set the ClientForTest as as parent of the socket and the widget as the parent of ClientForTest, they will be both cleaned up properly. If you use this->parent(), both will be destroyed "at the same time". However, one comes first and somtimes Qt changes the order, so your socket could be destroyed before the ClientForTest. The destructor of ClientForTest would crash. That won't happen if the socket is a child of the ClientForTest
The main difference between close() and disconnectFromHost() is that the first actually closes the OS socket, while the second does not. The problem is, after a socket was closed, you cannot use it to create a new connection. Thus, if you want to reuse the socket, use disconnectFromHost() otherwise close()
And regarding 3. and 4.:
What you are doing is creating the ClientForTest when the user clicks connect, and delete it as soon as he clicks disconnect. But thats no good design (IMHO). Since tcpSockForTest already is a member of the class, create it (via new) inside the constructor, and delete it in the destructor (optionally, because if you pass the widget as parent, Qt will delete it for you).
I know this question has been asked few times but all suggestions given there doesn't work for me.
Overview: I am implementing client server model and wants that as soon as msg arrived in server it should get displayed in main Qt widget. the widget , I choose to display msg is QLineEdit.
I have 3 files in project at the moment. Agent_A which is has all widget created dynamically. Then Server_test based on QTCPServer and sockClient for socket connection. I have received message on sockclient successfully from client but I don't know how to display it correctly on Agent_A .
I have added function in socketClient.cpp to update function in Agent_A but I guess when creating instance it always being NULL.
First a small snippet of my code and then what I have tried. may be you guys can input some valuable info.
Agent_A.h
class Agent_A : public QWidget
{
Q_OBJECT
public:
explicit Agent_A(QWidget *parent = 0);
void setLineEdit( const& modifyStr ); // function to change lineEditCmdString
~Agent_A();
private:
Ui::Agent_A *ui;
QPushButton *buttonStartServer;
QPushButton *buttonStopServer;
// some other widgets
QLabel *labelDisplay;
QLineEdit *lineEditCmdString;// I want to modify this value from sock client
ServerTest *server;
// few slots defined here
}
Agent_A.cpp
Agent_A::Agent_A( QWidget *parent ):
QWidget( parent ),
ui( new Ui::Agent_A )
{
//define push buttons
buttonStartServer = new QPushButton( tr( "&Start Server" ) );
buttonStopServer = new QPushButton( tr( "S&top" ));
// some properties of other widgets defined here which is not relevant to mention here
labelDisplay = new QLabel( tr("DisplayMessgae" ) );
lineEditCmdString = new QLineEdit;// I want to modify this value on sock client
labelDisplay->setBuddy( lineEditCmdString );
// define signals and slots for Server
connect( buttonStartServer, SIGNAL( clicked() ), this, SLOT( startServers() ) );
connect( buttonStopServer, SIGNAL( clicked() ), this, SLOT( stopServer() ) );
// some layout here which agian is not important to mention here.
ui->setupUi( this );
}
Agent_A::~Agent_A()
{
delete ui;
}
void Agent_A::setLineEdit( const Qstring& modifyStr )
{
lineEditCmdString->setText( modifyStr );
}
// now by socket client which creates socket
sockClient.h
class SockClient : public QObject
{
Q_OBJECT
public:
explicit SockClient( QObject *parent, QTcpSocket* socket= 0 );
~SockClient();
// I have added this function to update QLIneEdit in Agent_A
void updateTextinParent(const QString &changeText);
signals:
private slots:
void readClient();
private:
// some other functions
QTcpSocket *socketClient;
quint16 nextBlockSize;
public slots:
};
sockclient.cpp
// constructor for sockclient and some other functions
SockClient::SockClient( QObject *parent, QTcpSocket* socket ) : QObject( parent )
{
socketClient = socket ;
// create signals and slots
connect( socketClient, SIGNAL( readyRead() ), this, SLOT( readClient() ) );
connect( socketClient, SIGNAL( disconnected() ), this, SLOT( deleteLater() ) );
}
SockClient::~SockClient()
{
socketClient->close();
delete socketClient;
}
void SockClient::readClient()
{
QDataStream clientReadStream( socketClient );
clientReadStream.setVersion( QDataStream::Qt_4_3 );
QString strRecvFrm;
quint8 requestType;
clientReadStream >> nextBlockSize;
clientReadStream >> requestType;
if( requestType == 'S')
{
clientReadStream >> strRecvFrm;
}
qDebug() << " the string is " << strRecvFrm; // Has recieved correctly from client
updateTextinParent( strRecvFrmMops ); // Now trying to update widget
socketClient->close();
}
void SockClient::updateTextinParent( const QString& changeText )
{
if( this->parent() == 0 )
{
qDebug() << " Parent not assigned"; // This get printed ..
}
Agent_A *agent = qobject_cast< Agent_A* >( this->parent() ); // ?? is this is right way to do..?
if( agent != NULL )
{
qDebug() << " we are in updateTextin" << changeText; // it never get printed so I assume instance is always nULL
agent->setLineEdit( changeText );
}
}
// ServerTest.cpp where instance of sockClient is created
ServerTest::ServerTest(QObject *parent) : QObject(parent)
{
server = new QTcpServer( this );
}
void ServerTest::startServer()
{
connect( server, SIGNAL( newConnection() ), this, SLOT( incomingConnection() ) );
if( !server->listen( QHostAddress::Any, 9999) )
{
qDebug() << " Server failed to get started";
}
else
{
qDebug() << " Server started";
}
}
void ServerTest::stopServer()
{
server->close();
qDebug() << "Server closed";
}
ServerTest::~ServerTest()
{
server->close();
delete socketforClient;
delete server;
}
void ServerTest::incomingConnection()
{
socketforClient = new SockClient(this->parent(), server->nextPendingConnection() );
}
This is a very simple example:
qt.pro:
TEMPLATE = app
TARGET =
DEPENDPATH += .
INCLUDEPATH += .
# Input
HEADERS += classes.h
SOURCES += main.cpp
classes.h:
#include <QObject>
#include <QDebug>
class Agent_A : public QObject
{
Q_OBJECT
public slots:
void updateText(const QString &changeText) {
qDebug() << "updateText: " << changeText;
};
};
class SockClient : public QObject
{
Q_OBJECT
signals:
void updateTextinParent(const QString &text);
public:
void incomingText(const QString &text) {
emit updateTextinParent(text);
};
};
main.cpp:
#include "classes.h"
int main(int argc, char **argv) {
Agent_A *agent = new Agent_A;
SockClient client;
QObject::connect(&client, SIGNAL(updateTextinParent(const QString &)),
agent, SLOT(updateText(const QString &)));
client.incomingText(QString("hello"));
return 0;
}
Agent_A *agent = qobject_cast< Agent_A* >( this->parent() ); // ?? is this is right way to do..?
if( agent != NULL )
{
qDebug() << " we are in updateTextin" << changeText; // it never get printed so I assume instance is always nULL
agent->setLineEdit( chnageText );
}
Could you please check first that parent is not NULL?
And could you please show code where you create instance of SockClient?
Of course, you can't modify text because of you set as parent to socketClient object this pointer in Server_test class, so parent to socketClient will be Server_test but no Agent_A.
So make parent Agent_A for socketClient object:
socketforClient = new SockClient(this->parent(), server->nextPendingConnection());
Or you can make some others workarounds.
One more note: you make connection to newConnection() signal at your startServer method, not constructor. So if i start server, then stop them and start again server will be connected twice to signal and slot incomingConnection() will be called twice too. So you need disconnect at from signal at stopServer() method or do connection at constructor of class or use Qt::UniqueConnection.
I have problem with QUdpSocket. I want to create a simple program to send and receive data using the UDP protokol. I already read many similar topic but I do not found solved. Communication worked only for QHostAdress::LocalHost, then I give this same data as send, but if I want to send data to outside set concrete address, for example 194.181.161.134, that does not worked. That mean data is send but I can't receive. This is my code:
class Okno_GL : public QMainWindow
{
Q_OBJECT
public:
explicit Okno_GL(QWidget *parent = 0);
QWidget *wg;
QPushButton *pb;
QPushButton *pl;
QGridLayout *gr;
QUdpSocket *socket;
QHostAddress host;
QHostAddress bcast;
signals:
public slots:
void SLOT_Write();
void SLOT_load();
};
class Receiver : public QObject
{
Q_OBJECT
public:
Receiver();
QUdpSocket *udpSocket;
public slots:
void SLOT_processPendingDatagrams();
void SLOT_StCh(QAbstractSocket::SocketState state);
};
Okno_GL::Okno_GL(QWidget *parent) :
QMainWindow(parent)
{
pb = new QPushButton("write" , this);
pl = new QPushButton("read" , this);
wg = new QWidget(this);
setCentralWidget(wg);
gr = new QGridLayout(wg);
gr->addWidget(pb);
gr->addWidget(pl);
socket = new QUdpSocket(this);
connect(pb , SIGNAL(clicked()) , SLOT(SLOT_Write()));
connect(pl , SIGNAL(clicked()) , SLOT(SLOT_load()));
}
void Okno_GL::SLOT_Write()
{
QByteArray datagram = "gS";
int send;
send = socket->writeDatagram(datagram.data(), QHostAddress("194.181.161.134"), 1200);
}
void Okno_GL::SLOT_load()
{
}
Receiver::Receiver()
{
udpSocket = new QUdpSocket(this);
connect(udpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)) , this , SLOT(SLOT_StCh(QAbstractSocket::SocketState)));
if(udpSocket->bind(QHostAddress::Any , 1200))
{
qd "bind";
}
else
{
qd "not bind";
}
}
void Receiver::SLOT_processPendingDatagrams()
{
qd "receiver";
QByteArray datagram;
do {
datagram.resize(udpSocket->pendingDatagramSize());
udpSocket->readDatagram(datagram.data(), datagram.size());
} while (udpSocket->hasPendingDatagrams());
qd "datagram" << datagram;
}
void Receiver::SLOT_StCh(QAbstractSocket::SocketState state)
{
qd "slot" << state;
QByteArray datagram = "gS";
if ( state == QAbstractSocket::BoundState ) {
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(SLOT_processPendingDatagrams()) , Qt::QueuedConnection);
}
}
You should use write() instead of writeDatagram()
qint64 QUdpSocket::writeDatagram(const char * data, qint64 size, const QHostAddress & address, quint16 port)
Warning: Calling this function on a connected UDP socket may result in
an error and no packet being sent. If you are using a connected
socket, use write() to send datagrams.
So, I rebuild my code accordingly with your proposition. I add this line in construktor class Okno_GL.
socket = new QUdpSocket(this);
socket->connectToHost(QHostAddress("194.181.161.134") , 1200);
Here is slot to send
void Okno_GL::SLOT_Write()
{
QByteArray datagram = "gS";
int send;
// send = socket->writeDatagram(datagram.data(), QHostAddress("194.181.161.134"), 1200);
send = socket->write(datagram);
qd " send" << send;
}
Receiver code is not change, so I still white for signal readRedy() ,and I do not get him after send data.
PS. I whant to add that I have other option to connetc, is very very simply file command *bat whitch connect this host without any problem . This is proof that my network or admin nothing blocks (port , ip);
Pss thanks for your interest
Problem solved ! It is very stupid mistake. I should be send 3 bajt instead 2. The 3 bajt it is 0x0D.
Following code is work
socket = new QUdpSocket(this);
socket->bind(QHostAddress::Any, 1200);
and send
QByteArray datagram = "gS";
datagram.append(0x0D);
int send;
send = socket->writeDatagram(datagram.data(), QHostAddress("194.181.161.134"), 1200);
and receive after signal readyRead()
qd "receiver";
QByteArray datagram;
do {
datagram.resize(socket->pendingDatagramSize());
socket->readDatagram(datagram.data(), datagram.size());
} while (socket->hasPendingDatagrams());
qd "datagram" << datagram;
very help mi wireshark. Thanks for all
This question already has an answer here:
Bind a QTcpSocket to a specific port
(1 answer)
Closed 2 years ago.
I'm using QTcpSocket to communicate between two applications. one is a c++ program and the other one is a web page written in PHP.
The goal is to send data from my webpage to my c++ program using sockets.
I don't know how to open a connection on a specific port e.g 12345 and listen to it if I got any data or not ..
I've written the following code so far:
MainWindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
Mysocket = new QSocket(this);
Mysocket->Initialization();
}
MainWindow::~MainWindow()
{
delete ui;
}
QSocket.cpp
#include "qsocket.h"
#define SOCKET_PORT 12345
QSocket::QSocket(QObject *parent) :
QObject(parent)
{
}
void QSocket::Initialization()
{
//connected
socket = new QTcpSocket(this);
socket->connectToHost("localhost",SOCKET_PORT);
connect(socket,SIGNAL(connected()),this,SLOT(connected()));
connect(socket,SIGNAL(disconnected()),this,SLOT(disconnected()));
connect(socket,SIGNAL(bytesWritten(qint64)),this,SLOT(bytesWritten(qint64)));
connect(socket,SIGNAL(readyRead()),this,SLOT(readyRead()));
if(!socket->waitForConnected(1000))
{
QMessageBox::StandardButton reply;
reply = QMessageBox::question(0,"Error","Error in Socket Connection",
QMessageBox::Yes|QMessageBox::No);
socket->close();
}
socket80->close();
}
void QSocket::connected()
{
QMessageBox::StandardButton reply;
int PortNumber = socket->localPort();
reply = QMessageBox::question(0,"Connected","Socket Connection is Established",
QMessageBox::Yes|QMessageBox::No);
qDebug()<<"I'm Listening to Port: "<<PortNumber<<"on the local host \n";
}
void QSocket::disconnected()
{
qDebug()<<"Disconnected .... \n";
socket->close();
}
void QSocket::bytesWritten(qint64 bytes)
{
qDebug()<<"We wrote "<<bytes<<" \n";
}
void QSocket::readyRead()
{
qDebug()<<"Reading .... \n";
qDebug()<<socket->bytesAvailable();
qDebug()<<socket->readAll();
}
When I run this code it doesn't open any connection and gives error and it enters into this if statement ..
if(!socket->waitForConnected(1000))
{
QMessageBox::StandardButton reply;
reply = QMessageBox::question(0,"Error","Error in Socket Connection",
QMessageBox::Yes|QMessageBox::No);
socket->close();
}
if I changed the port number to 80 it works fine and all the functions work properly.
By reading some posts in SO I've realized that a solution would be to use QTcpServer but I don't have any specific experience in it.
What's the problem in here ?!
P.S.
My Platform Specs.
Ubuntu 13.10
Qt 5.2.1
You can use the following sample server. You can start listening on a port by calling start_listen(int port_no).
#include <QtNetwork>
#include <QMessageBox>
class server : public QTcpServer {
Q_OBJECT
public:
explicit server(QObject *parent = 0);
~server();
QTcpSocket server_socket;
public slots:
void tcpReady();
void tcpError( QAbstractSocket::SocketError error );
bool start_listen(int port_no);
protected:
void incomingConnection( int descriptor );
};
server::server(QObject *parent) : QTcpServer(parent) {
connect( &server_socket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(tcpError(QAbstractSocket::SocketError)) );
connect( &server_socket, SIGNAL(readyRead()),
this, SLOT(tcpReady()) );
server_socket.setSocketOption(QAbstractSocket::KeepAliveOption, true );
}
server::~server() {
server_socket.disconnectFromHost();
server_socket.waitForDisconnected();
}
void server::tcpReady() {
QByteArray array = server_socket.read(erver_socket.bytesAvailable());
}
void server::tcpError(QAbstractSocket::SocketError error) {
QMessageBox::warning( (QWidget *)this->parent(), tr("Error"),tr("TCP error: %1").arg( server_socket.errorString() ) );
}
bool server::start_listen(int port_no) {
if( !this->listen( QHostAddress::Any, port_no ) ) {
QMessageBox::warning( (QWidget *)this->parent(), tr("Error!"), tr("Cannot listen to port %1").arg(port_no) );
}
else
return true;
}
void server::incomingConnection(int descriptor) {
if( !server_socket.setSocketDescriptor( descriptor ) ) {
QMessageBox::warning( (QWidget *)this->parent(), tr("Error!"), tr("Socket error!") );
return;
}
}