我正在实现基于Qt的TCP-Ip服务器的客户端,但是当我关闭连接时程序崩溃并通过点击连接按钮再次启动。
项目概述。我有两个lineEdit的Qwidget(主应用程序)供用户输入端口号和服务器IP地址。 它还有2个连接到服务器和断开连接的按钮。在点击连接按钮时,它将调用客户端套接字的构造函数并调用connectToHost。
测试:尝试在同一台计算机上进行测试,服务器在端口6000上运行,ip地址为127.0.0.1。
问题:当我启动客户端应用程序时。输入端口号和地址并按下连接按钮,它成功连接。我可以成功写入服务器。然后我点击断开连接按钮并成功断开连接,但之后如果我再次通过点击连接按钮连接它会崩溃。我知道问题在于tcpSocket,但不知道如何修复它。
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();
}
答案 0 :(得分:2)
有些事情可能会导致您的崩溃:
ClientForTest
构造函数中的信号,但稍后会创建套接字本身。那不会奏效。在连接sockFortest = new QTcpSocket(this);
移动到构造函数
this
代替this->parent()
this
为父级的构造函数内创建套接字,即可。在connectToServer
中,建立连接,然后在disconnectToServer
中使用disconnectFromHost
关闭它。 startClient
和stopClient
也是如此。创建一次对象,只使用连接/断开功能,不删除。如果需要代码,我可以添加一些。
自从被要求以来,这里有更多解释:
ClientForTest
也是QObject
。如果将ClientForTest
设置为套接字的父级,将小组件设置为ClientForTest
的父级,则它们将被正确清理。如果您使用this->parent()
,则两者都将被销毁&#34;同时#34;。但是,首先是Qt更改顺序,因此您的套接字可能会在ClientForTest
之前销毁。 ClientForTest
的析构函数会崩溃。如果套接字是ClientForTest
close()
和disconnectFromHost()
之间的主要区别在于第一个实际上关闭了OS套接字,而第二个实际上没有。问题是,在套接字关闭后,您无法使用它来创建新连接。因此,如果要重用套接字,请使用disconnectFromHost()
,否则close()
关于3.和4:
您正在执行的操作是在用户单击“连接”时创建ClientForTest
,并在单击断开连接后立即将其删除。但那没有好的设计(恕我直言)。由于tcpSockForTest
已经是类的成员,因此在构造函数中创建它(通过new),并在析构函数中删除它(可选地,因为如果您将小部件作为父级传递,Qt将为您删除它)。