QAbstractSocket类发出的报错信号error(QAbstractSocket::SocketError)在个人使用过程中发现一个细节,经查找资料后做了信号连接异步处理: 当服务端关闭的时候,错误码为RemoteHostClosedError,可状态码却还是ConnectedState,这时候需要确保该报错流程生命周期完结,以使得可以得到应得的其它状态码; connect(this, &TcpClient::signal_disconnected, this, &TcpClient::slot_disconnected, Qt::QueuedConnection); 源码中,我使用Qt::QueuedConnection来关联连接,以保证上文提到的生命周期完结; 具体源码如下: TcpClient.h #ifndef TcpClient_H #define TcpClient_H #include <QTcpSocket> #include <QTimer> /** 配套ColorTestServer(服务端)使用的客户端(含心跳和重连),输出状态及接收到的消息 */ class TcpClient : public QObject { Q_OBJECT public: TcpClient(QObject *parent = nullptr); ~TcpClient(); /** 创建客户端:server_ip-服务端ip地址,server_tcp_port-服务端tcp端口号 */ void CreateClient(const QString &server_ip, const unsigned int &server_tcp_port); /** 释放客户端 */ void ReleaseClient(); /** 发送消息:client_msg-客户端消息 */ bool ClientSend(const char *client_msg); private: /** 服务端ip地址 */ QString m_server_ip; /** 服务端tcp端口号 */ unsigned int m_server_tcp_port; /** tcp客户端 */ QTcpSocket *m_TcpSocket; /** 定时器:心跳 */ QTimer *m_Timer; /** 接收缓存 */ std::string m_RecvBuf; private slots: /** 连接 */ void slot_TcpSocket_connected(); /** 错误 */ void slot_TcpSocket_error(QAbstractSocket::SocketError); /** 断开 */ void slot_disconnected(); /** 定时器:心跳 */ void slot_Timer_timeout(); /** 待读取 */ void slot_TcpSocket_readyRead(); signals: /** 断开 */ void signal_disconnected(); /** 输出状态及接收到的消息:state-状态(0断开、1建立连接、2收到消息),server_msg-服务端消息(状态为2时才有数据),server_msg_len-服务端消息长度 */ void signal_StateAndMsgOut(const unsigned int &state, const char *server_msg, const unsigned int &server_msg_len); }; #endif TcpClient.cpp #include "TcpClient.h" TcpClient::TcpClient(QObject *parent) : QObject(parent) { m_server_ip = ""; m_server_tcp_port = 0; m_TcpSocket = nullptr; m_Timer = nullptr; m_RecvBuf = ""; connect(this, &TcpClient::signal_disconnected, this, &TcpClient::slot_disconnected, Qt::QueuedConnection); } TcpClient::~TcpClient() { ReleaseClient(); } void TcpClient::CreateClient(const QString &server_ip, const unsigned int &server_tcp_port) { if(m_TcpSocket != nullptr) { return ; } m_server_ip = server_ip; m_server_tcp_port = server_tcp_port; m_TcpSocket = new QTcpSocket(); connect(m_TcpSocket, &QTcpSocket::connected, this, &TcpClient::slot_TcpSocket_connected); connect(m_TcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(slot_TcpSocket_error(QAbstractSocket::SocketError))); connect(m_TcpSocket, &QTcpSocket::readyRead, this, &TcpClient::slot_TcpSocket_readyRead); m_TcpSocket->connectToHost(m_server_ip, m_server_tcp_port); m_Timer = new QTimer(); connect(m_Timer, &QTimer::timeout, this, &TcpClient::slot_Timer_timeout); m_Timer->start(60000); } void TcpClient::ReleaseClient() { if(m_Timer != nullptr) { m_Timer->stop(); delete m_Timer; m_Timer = nullptr; } if(m_TcpSocket != nullptr) { delete m_TcpSocket; m_TcpSocket = nullptr; } } void TcpClient::slot_TcpSocket_connected() { emit signal_StateAndMsgOut(1, nullptr, 0); } void TcpClient::slot_TcpSocket_error(QAbstractSocket::SocketError) { emit signal_disconnected();//这个信号关联的时候必须用Qt::QueuedConnection异步处理,因为当服务端关闭的时候,错误码为RemoteHostClosedError,可状态码却还是ConnectedState,即先需要该报错流程生命周期完结 } void TcpClient::slot_disconnected() { emit signal_StateAndMsgOut(0, nullptr, 0); m_TcpSocket->abort(); m_TcpSocket->connectToHost(m_server_ip, m_server_tcp_port); } void TcpClient::slot_Timer_timeout() { if(m_TcpSocket->state() == QTcpSocket::ConnectedState) { std::string ssSend = (char)0x02 + std::string("{\"type\":4}") + (char)0x03; m_TcpSocket->write(ssSend.c_str()); } } void TcpClient::slot_TcpSocket_readyRead() { m_RecvBuf += m_TcpSocket->readAll(); while (true) { std::string::size_type ssst_pos = m_RecvBuf.find_first_of((char)0x03); if(ssst_pos != std::string::npos) { std::string ssCurRecv = m_RecvBuf.substr(1, ssst_pos-1); emit signal_StateAndMsgOut(2, ssCurRecv.c_str(), (unsigned int)ssCurRecv.length()); m_RecvBuf = m_RecvBuf.substr(ssst_pos+1, m_RecvBuf.length()-ssst_pos); } else { if(m_RecvBuf.length() >= 1024*1024) { m_RecvBuf = ""; } break; } } } bool TcpClient::ClientSend(const char *client_msg) { if(m_TcpSocket == nullptr) { return false; } if(m_TcpSocket->state() != QTcpSocket::ConnectedState) { return false; } std::string ssSend = (char)0x02 + std::string(client_msg) + (char)0x03; if(m_TcpSocket->write(ssSend.c_str()) == -1) { return false; } return true; } 源码是用于项目的,故里面有消息拆分的部分
qt-基于QTcpSocket的tcp客户端
于 2023-06-05 14:57:03 首次发布