效果图:
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);
}