C++ 断开Qt后连接到服务器时客户端程序崩溃
我正在基于Qt实现TCP Ip服务器的客户端,但当我关闭连接并点击connect按钮重新启动时,程序崩溃 项目概述。我有Qwidget(主应用程序),带有2行编辑功能,用户可以输入端口号和服务器Ip地址。 它还有两个按钮,分别连接到服务器和断开连接。点击connect按钮,它将调用客户端套接字的构造函数并调用connectToHost 测试:尝试在同一台计算机上进行测试,服务器在端口6000和ip地址127.0.0.1上运行 问题:当我启动客户端应用程序,输入端口号和地址,点击连接按钮,它成功连接。我可以成功地写入服务器。然后,我单击“断开连接”按钮,它成功地断开连接,但之后,如果我再次单击“连接”按钮进行连接,它将崩溃。我知道问题出在tcpSocket上,但不知道如何解决它 clientAgent(QWidget应用程序).h ClientAgent.cppC++ 断开Qt后连接到服务器时客户端程序崩溃,c++,qt,tcp-ip,qtcpsocket,C++,Qt,Tcp Ip,Qtcpsocket,我正在基于Qt实现TCP Ip服务器的客户端,但当我关闭连接并点击connect按钮重新启动时,程序崩溃 项目概述。我有Qwidget(主应用程序),带有2行编辑功能,用户可以输入端口号和服务器Ip地址。 它还有两个按钮,分别连接到服务器和断开连接。点击connect按钮,它将调用客户端套接字的构造函数并调用connectToHost 测试:尝试在同一台计算机上进行测试,服务器在端口6000和ip地址127.0.0.1上运行 问题:当我启动客户端应用程序,输入端口号和地址,点击连接按钮,它成功连
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.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();
}
ClientForTest::ClientForTest(QString hostAddr、quint16 portNum、QObject*parent):
主机名(hostAddr),
端口号(portNum),
QObject(父对象)
{
连接(sockFortest,信号(connected()),此,插槽(connectedToTest());
连接(sockFortest,信号(disconnected()),此,插槽(connectionClosedByServer());
连接(sockFortest,信号(error(QAbstractSocket::socketterror)),此,插槽(error());
storeLineEditMsg=“”;
}
void ClientForTest::executeSignals()
{
//事实上,我需要把它放在后面的构造函数中
连接(此,信号(sigSendData()),此,插槽(connectedToTest());
}
ClientForTest::~ClientForTest()
{
sockFortest->close();
删除sockFortest;
}
boolclientfortest::connectToServer()
{
sockFortest=new QTcpSocket(this->parent());//这里可能有问题,但如何解决?
sockFortest->connectToHost(主机名、端口号);
nextBlockSize=0;
executeSignals();
返回sockFortest->waitForConnected(1000);
}
void ClientForTest::disconnectToServer()
{
sockFortest->close();
//sockFortest.close();
qDebug()父对象();
if(connectToServer()==true)
{
qDebug()状态()==QTcpSocket::ConnectedState)
{
qDebug()有几件事可能是导致崩溃的原因:
- 您连接了
ClientForTest
构造函数内的信号,但套接字本身是稍后创建的。这将不起作用。在连接之前,将行sockFortest=new qtcsocket(this);
移动到构造函数
- 同一行,使用
this
代替this->parent()
- 最后:您可以在多个位置创建/删除套接字。不要这样做。在构造函数中创建套接字,并将
this
作为父项,就是这样。在connectToServer
中,建立连接,然后在disconnectToServer
中,使用disconnectFromHost
关闭它。也一样de>startClient
和stopClient
。创建对象一次,只需使用连接/断开连接功能,无需删除
如果需要代码,我可以添加一些
由于有人提出要求,这里有更多的解释:
ClientForTest
也是一个QObject
。如果您将ClientForTest
设置为套接字的父项,将小部件设置为ClientForTest
的父项,它们都将被正确清理。如果您使用this->parent()
,两者都将被销毁“同时”。但是,一个先到,有时Qt会更改顺序,因此您的套接字可能会在ClientForTest
之前被销毁。ClientForTest
的析构函数会崩溃。如果套接字是ClientForTest
close()
和disconnectFromHost()
之间的主要区别在于第一个实际关闭了操作系统套接字,而第二个没有。问题是,套接字关闭后,您无法使用它来创建新连接。因此,如果要重用套接字,请使用disconnectFromHost()
否则close()
您所做的是在用户单击connect时创建
ClientForTest
,并在单击disconnect时将其删除。但这不是一个好的设计(IMHO)。由于tcpSockForTest
已经是类的一员,所以在构造函数中创建它(通过new),然后在析构函数中删除它(可选,因为如果您将小部件作为父部件传递,Qt将为您删除它)。您调试过应用程序以查看它在哪一行崩溃吗?@BowDzone,是的,它在的构造函数中崩溃ClientForTest@Bowdzone,如果我将构造函数中定义的所有连接都带到函数executeSignals()它工作得很好。但是现在我想知道我添加了太多的delete和new调用。有更好的方法吗?您不必每次断开连接时都删除qtcsocket
对象,每次连接时都创建它的新实例。只需在构造函数中初始化一个实例即可。但是问题是似乎是您的ClientForTest
构造函数。您连接了sockFortest
对象的信号,但此对象尚未初始化。您正在使用未初始化的指针。正是如此。每次建立新连接时,您都会创建一个新的qtcsocket
对象。断开连接时,您会删除该对象t、 我不知道您的应用程序到底是如何工作的,但它似乎没有必要。您只需在构造函数中创建一次qtcsocket
对象,然后使用该实例。qtcsocket
是QObject的子类<
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::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();
}