效果图:
知识点
tcpServer
.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTcpServer>
#include <QLabel>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
// 1、 标签栏变量
QLabel *labListen; //状态栏标签
QLabel *labSocketState; //状态栏标签:套接字的状态
QTcpServer *tcpServer; // TCP服务器:负责监听
QTcpSocket *tcpSocket=nullptr; //TCP通讯的Socket
QString getLocalIP(); //获取本机IP地址
private slots:
//自定义槽函数
void do_newConnection(); //关联QTcpServer的newConnection()信号
void do_clientConnected(); //客户端 socket 已连接
void do_clientDisconnected(); //客户端 socket 已断开
void do_socketReadyRead(); //读取socket传入的数据
void do_socketStateChange(QAbstractSocket::SocketState socketState);
void on_actStart_triggered();
void on_actStop_triggered();
void on_btnSend_clicked();
void on_actClear_triggered();
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
.cpp
重点代码:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QHostInfo>
#include <QtNetwork>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 1、标签栏放监听状态和Socket状态:
labListen=new QLabel("监听状态:"); // 创建
labListen->setMinimumWidth(150); // 设置
ui->statusBar->addWidget(labListen); // 放
labSocketState=new QLabel("Socket状态:");
labSocketState->setMinimumWidth(200);
ui->statusBar->addWidget(labSocketState);
// 2、标题栏放本机IP地址
QString localIP=getLocalIP(); //获取本机IP
this->setWindowTitle(this->windowTitle()+"----本机IP地址:"+localIP);
ui->comboIP->addItem(localIP);
// 3、连接tcpServer和do_newConnection
tcpServer=new QTcpServer(this);
// 当有客户端接入时,tcpServer发送newConnection信号;此信号关联槽函数do_newConnection
connect(tcpServer,SIGNAL(newConnection()),this,SLOT(do_newConnection()));
}
QString MainWindow::getLocalIP()
{//获取本机IPv4地址
QString hostName=QHostInfo::localHostName(); // get :本地主机名
QHostInfo hostInfo=QHostInfo::fromName(hostName);
QString localIP="";
QList<QHostAddress> addList=hostInfo.addresses(); //本机IP地址列表
if (addList.isEmpty())
return localIP;
foreach(const auto& aHost, addList)
if (QAbstractSocket::IPv4Protocol==aHost.protocol())
{
localIP=aHost.toString();
break;
}
return localIP;
}
void MainWindow::do_newConnection()
{
// 通过nextPendingConnection()函数获取与连接的客户端进行通信的QTcpSocket 对象 tcpSocket,
// 然后将 tcpSocket的几个信号与相应的槽函数连接起来。
tcpSocket = tcpServer->nextPendingConnection(); //创建socket
connect(tcpSocket, SIGNAL(connected()),this, SLOT(do_clientConnected()));
do_clientConnected(); //执行一次槽函数,显示状态
connect(tcpSocket, SIGNAL(disconnected()),this, SLOT(do_clientDisconnected()));
connect(tcpSocket,&QTcpSocket::stateChanged,this,&MainWindow::do_socketStateChange);
do_socketStateChange(tcpSocket->state()); //执行一次槽函数,显示状态
// QTcpSocket对象接收到数据后会发射readyRead信号,连接槽函数
connect(tcpSocket,SIGNAL(readyRead()), this,SLOT(do_socketReadyRead()));
}
void MainWindow::do_socketReadyRead()
{//读取缓冲区的行文本
while(tcpSocket->canReadLine()) // canReadLine()判断是否有新的一行数据需要读取
ui->textEdit->appendPlainText("[in] "+tcpSocket->readLine());
}
void MainWindow::do_clientConnected()
{//客户端接入时
ui->textEdit->appendPlainText("**client socket connected");
ui->textEdit->appendPlainText("**peer address:"+
tcpSocket->peerAddress().toString()); // 找到另一端的地址
ui->textEdit->appendPlainText("**peer port:"+
QString::number(tcpSocket->peerPort())); // 另一端的端口号
}
void MainWindow::do_clientDisconnected()
{//客户端断开连接时
ui->textEdit->appendPlainText("**client socket disconnected");
tcpSocket->deleteLater();
}
void MainWindow::do_socketStateChange(QAbstractSocket::SocketState socketState)
{//socket状态变化时
switch(socketState)
{
case QAbstractSocket::UnconnectedState:
labSocketState->setText("socket状态:UnconnectedState");
break;
case QAbstractSocket::HostLookupState:
labSocketState->setText("socket状态:HostLookupState");
break;
case QAbstractSocket::ConnectingState:
labSocketState->setText("socket状态:ConnectingState");
break;
case QAbstractSocket::ConnectedState:
labSocketState->setText("socket状态:ConnectedState");
break;
case QAbstractSocket::BoundState:
labSocketState->setText("socket状态:BoundState");
break;
case QAbstractSocket::ClosingState:
labSocketState->setText("socket状态:ClosingState");
break;
case QAbstractSocket::ListeningState:
labSocketState->setText("socket状态:ListeningState");
}
}
MainWindow::~MainWindow()
{//析构函数:确保窗口关闭时断开与TCP客户端的socket连接
if (tcpSocket != nullptr)
{
if (tcpSocket->state()==QAbstractSocket::ConnectedState)
tcpSocket->disconnectFromHost(); //断开与客户端的连接
}
if (tcpServer->isListening())
tcpServer->close(); //停止网络监听
delete ui;
}
void MainWindow::on_actStart_triggered()
{//"开始监听"按钮
QString IP=ui->comboIP->currentText(); // 拿:IP地址字符串,如"127.0.0.1"
quint16 port=ui->spinPort->value(); // 拿:端口
QHostAddress address(IP); // 将IP从字符串转成地址
// 调用监听函数(主机地址,端口号)
tcpServer->listen(address,port); //开始监听
// tcpServer->listen(QHostAddress::LocalHost,port);// Equivalent to QHostAddress("127.0.0.1").
ui->textEdit->appendPlainText("**开始监听...");
ui->textEdit->appendPlainText("**服务器地址:"+tcpServer->serverAddress().toString());
ui->textEdit->appendPlainText("**服务器端口:"+QString::number(tcpServer->serverPort()));
ui->actStart->setEnabled(false);
ui->actStop->setEnabled(true);
labListen->setText("监听状态:正在监听");
}
void MainWindow::on_actStop_triggered()
{//"停止监听"按钮
if (tcpServer->isListening()) //tcpServer正在监听
{
if (tcpSocket != nullptr)
if (tcpSocket->state()==QAbstractSocket::ConnectedState)
tcpSocket->disconnectFromHost();
tcpServer->close(); //停止监听
ui->actStart->setEnabled(true);
ui->actStop->setEnabled(false);
labListen->setText("监听状态:已停止监听");
}
}
void MainWindow::on_btnSend_clicked()
{//"发送消息"按钮,发送一行字符串,以换行符结束
// 没有连接上时
if(tcpSocket == nullptr)
{
ui->textEdit->appendPlainText("没有连接成功");
return;
}
QString msg=ui->editMsg->text(); // get msg
ui->textEdit->appendPlainText("[out] "+msg);
ui->editMsg->clear();
ui->editMsg->setFocus();
QByteArray str=msg.toUtf8(); // QString转成QByteArray
str.append('\n'); //添加一个换行符
tcpSocket->write(str); // 将str写入缓存区,要求QByteArray格式
}
void MainWindow::on_actClear_triggered()
{
ui->textEdit->clear();
}
tcpClient
.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTcpSocket>
#include <QLabel>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
QTcpSocket *tcpClient; //socket
QLabel *labSocketState; //状态栏显示标签
QString getLocalIP(); //获取本机IP地址
private slots:
//自定义槽函数
void do_connected();
void do_disconnected();
void do_socketStateChange(QAbstractSocket::SocketState socketState);
void do_socketReadyRead();//读取socket传入的数据
void on_actConnect_triggered();
void on_actDisconnect_triggered();
void on_btnSend_clicked();
void on_actClear_triggered();
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QHostInfo>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
tcpClient=new QTcpSocket(this); //创建socket变量
labSocketState=new QLabel("Socket状态:"); //状态栏标签
labSocketState->setMinimumWidth(250);
ui->statusBar->addWidget(labSocketState);
QString localIP=getLocalIP(); //获取本机IP
this->setWindowTitle(this->windowTitle()+"----本机IP地址:"+localIP);
ui->comboServer->addItem(localIP);
connect(tcpClient,SIGNAL(connected()), this,SLOT(do_connected()));
connect(tcpClient,SIGNAL(disconnected()),this,SLOT(do_disconnected()));
connect(tcpClient,&QTcpSocket::stateChanged,this,&MainWindow::do_socketStateChange);
connect(tcpClient,SIGNAL(readyRead()), this,SLOT(do_socketReadyRead()));
}
MainWindow::~MainWindow()
{
delete ui;
}
QString MainWindow::getLocalIP()
{
QString hostName=QHostInfo::localHostName(); //本地主机名
QHostInfo hostInfo=QHostInfo::fromName(hostName);
QString localIP="";
QList<QHostAddress> addList=hostInfo.addresses();
if (addList.isEmpty())
return localIP;
foreach(QHostAddress aHost, addList)
if (QAbstractSocket::IPv4Protocol==aHost.protocol())
{
localIP=aHost.toString();
break;
}
return localIP;
}
void MainWindow::do_connected()
{ //connected()信号的槽函数
ui->textEdit->appendPlainText("**已连接到服务器");
ui->textEdit->appendPlainText("**peer address:"+
tcpClient->peerAddress().toString());
ui->textEdit->appendPlainText("**peer port:"+
QString::number(tcpClient->peerPort()));
ui->actConnect->setEnabled(false);
ui->actDisconnect->setEnabled(true);
}
void MainWindow::do_disconnected()
{//disConnected()信号的槽函数
ui->textEdit->appendPlainText("**已断开与服务器的连接");
ui->actConnect->setEnabled(true);
ui->actDisconnect->setEnabled(false);
}
void MainWindow::do_socketStateChange(QAbstractSocket::SocketState socketState)
{//stateChange()信号的槽函数
switch(socketState)
{
case QAbstractSocket::UnconnectedState:
labSocketState->setText("socket状态:UnconnectedState");
break;
case QAbstractSocket::HostLookupState:
labSocketState->setText("socket状态:HostLookupState");
break;
case QAbstractSocket::ConnectingState:
labSocketState->setText("socket状态:ConnectingState");
break;
case QAbstractSocket::ConnectedState:
labSocketState->setText("socket状态:ConnectedState");
break;
case QAbstractSocket::BoundState:
labSocketState->setText("socket状态:BoundState");
break;
case QAbstractSocket::ClosingState:
labSocketState->setText("socket状态:ClosingState");
break;
case QAbstractSocket::ListeningState:
labSocketState->setText("socket状态:ListeningState");
}
}
void MainWindow::do_socketReadyRead()
{//readyRead()信号的槽函数
while(tcpClient->canReadLine())
ui->textEdit->appendPlainText("[in] "+tcpClient->readLine());
}
void MainWindow::on_actConnect_triggered()
{//“连接服务器”按钮
QString addr=ui->comboServer->currentText(); // 拿:地址
quint16 port=ui->spinPort->value(); // 拿:端口
tcpClient->connectToHost(addr,port);
// tcpClient->connectToHost(QHostAddress::LocalHost,port);
}
void MainWindow::on_actDisconnect_triggered()
{//“断开连接”按钮
if (tcpClient->state()==QAbstractSocket::ConnectedState)
tcpClient->disconnectFromHost();
}
void MainWindow::on_btnSend_clicked()
{//“发送数据”按钮
QString msg=ui->editMsg->text(); // 拿:数据
ui->textEdit->appendPlainText("[out] "+msg);
ui->editMsg->clear();
ui->editMsg->setFocus();
QByteArray str=msg.toUtf8();
str.append('\n');
tcpClient->write(str);
}
void MainWindow::on_actClear_triggered()
{
ui->textEdit->clear();
}