效果圖:
TCP/UDP調試助手之TCP客戶端,支持錯誤信息顯示,斷開連接後及時釋放資源。
一、關鍵代碼
1.在.pro文件中添加QT += network,包含頭文件#include <QTcpSocket>
在類裏定義一個QTcpSocket*成員m_tcpSocket
QTcpSocket* m_tcpSocket;
2.界面校驗設置。界面上有兩個lineEdit用來填寫服務器的IP和端口,通過setValidator可以限制lineEdit輸入的範圍,端口號範圍0-65535,IP地址用正則表達式校驗,防止輸入錯誤。
//設置端口輸入校驗
ui->lineEdit_clientRemotePort->setValidator(new QIntValidator(0,65535));
//ip校驗正則
QRegExp regExpIP("((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])[\\.]){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])");
//設置IP輸入校驗
ui->lineEdit_clientRemoteIP->setValidator(new QRegExpValidator(regExpIP ,ui->lineEdit_serverLocalIp));
3.連接斷開主要用到三個函數和兩個信號。
3.1 通過調用m_tcpSocket->connectToHost(ip,port);開始嘗試連接服務器;
3.2 m_tcpSocket->waitForConnected(1000)設置等待的時間,等待連接。在這裏設置1000ms,1000ms內連上服務器,返回true ,沒連上返回false;
3.3 m_tcpSocket->abort();//終止連接,並且是立即關閉;
3.4 信號error(QAbstractSocket::SocketError),發生錯誤時發送信號,並傳遞錯誤信息;
3.5 信號readyRead(),接收到數據時發送的信號。
//tcp客戶端連接/斷開
void MainWindow::on_btn_clientConnect_clicked()
{
if(m_tcpSocket == nullptr)
{
//獲取本地端口
bool ok;
quint16 port=ui->lineEdit_clientRemotePort->text().toUShort(&ok);
if(!ok)
{
QMessageBox::warning(this,"錯誤","遠程端口設置有誤,請重新輸入");
return;
}
//獲取本地Ip
QHostAddress ip(ui->lineEdit_clientRemoteIP->text());
ip.toIPv4Address(&ok);
if(!ok)
{
QMessageBox::warning(this,"錯誤","遠程ip設置有誤,請重新輸入");
return;
}
this->m_tcpSocket=new QTcpSocket(this);
m_tcpSocket->connectToHost(ip,port);
connect(m_tcpSocket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(ClientReadError(QAbstractSocket::SocketError)));
//等待連接
if (m_tcpSocket->waitForConnected(1000))
{
connect(m_tcpSocket,SIGNAL(readyRead()),this,SLOT(ClinetReadData()));
//更新UI
ui->text_clientRec->appendPlainText("已連接服務器"+QString("[%1:%2]\r\n").arg(ui->lineEdit_clientRemoteIP->text()).arg(ui->lineEdit_clientRemotePort->text()));
ui->btn_clientConnect->setText("斷開");
ui->btn_clientConnect->setIcon(QIcon(":/Resource/Img/stop36x36.png"));
ui->lineEdit_clientRemoteIP->setEnabled(false);
ui->lineEdit_clientRemotePort->setEnabled(false);
}
else//連接失敗
{
m_tcpSocket->disconnect();
m_tcpSocket->deleteLater();
m_tcpSocket=nullptr;
ui->text_clientRec->appendPlainText("連接失敗"+QString("[%1:%2]\r\n").arg(ui->lineEdit_clientRemoteIP->text()).arg(ui->lineEdit_clientRemotePort->text()));
}
}
else
{
m_tcpSocket->disconnect();//斷開信號槽
m_tcpSocket->abort();//終止
m_tcpSocket->deleteLater();//釋放
m_tcpSocket=nullptr;
//更新UI
ui->text_clientRec->appendPlainText("已斷開服務器"+QString("[%1:%2]\r\n").arg(ui->lineEdit_clientRemoteIP->text()).arg(ui->lineEdit_clientRemotePort->text()));
ui->btn_clientConnect->setText("連接");
ui->btn_clientConnect->setIcon(QIcon(":/Resource/Img/start36x36.png"));
ui->lineEdit_clientRemoteIP->setEnabled(true);
ui->lineEdit_clientRemotePort->setEnabled(true);
}
}
4. readyRead()信號觸發的讀取數據槽函數,調用m_tcpSocket->readAll();讀取所有接收到的數據
//tcp客戶端讀取數據
void MainWindow::ClinetReadData()
{
QByteArray ba = m_tcpSocket->readAll();
QString data;
//hex
if(ui->chk_udpRecHex->isChecked())
{
this->ByteToHexString(data,ba);
}
else//普通字符串
{
data=QString::fromLocal8Bit(ba);
}
//顯示
ui->text_clientRec->insertPlainText(data);
ui->text_clientRec->moveCursor(QTextCursor::End);
}
5. 發送數據, 通過調用m_tcpSocket->write(byteArray);寫入數據
//點擊tcp客戶端發送
void MainWindow::on_btn_clientSend_clicked()
{
QByteArray byteArray;
QString data=ui->text_clientSend->toPlainText();
//Hex發送
if(ui->chk_clientSendHex->isChecked())
{
//hex字符串轉字節
if(!HexStringToByte(data,byteArray))
{
QMessageBox::information(this,"提示","輸入的十六進制字符串有誤,請重新輸入");
return;
}
}
//普通字符串發送
else
{
byteArray= data.toLocal8Bit();
}
m_tcpSocket->write(byteArray);
}
6. error(QAbstractSocket::SocketError)信號槽函數,顯示錯誤信息並直接斷開連接
//tcp客戶端發生錯誤
void MainWindow::ClientReadError(QAbstractSocket::SocketError)
{
QString err=QString("發生錯誤:%1").arg(m_tcpSocket->errorString());
ui->text_clientRec->appendPlainText(err);
m_tcpSocket->disconnect();//斷開所有信號
m_tcpSocket->abort();//終止socket連接
m_tcpSocket->deleteLater();//釋放
m_tcpSocket=nullptr;
//更新UI
ui->text_clientRec->appendPlainText("已斷開服務器"+QString("[%1:%2]\r\n").arg(ui->lineEdit_clientRemoteIP->text()).arg(ui->lineEdit_clientRemotePort->text()));
ui->btn_clientConnect->setText("連接");
ui->btn_clientConnect->setIcon(QIcon(":/Resource/Img/stop36x36.png"));
ui->lineEdit_clientRemoteIP->setEnabled(true);
ui->lineEdit_clientRemotePort->setEnabled(true);
}