Qt網絡通信服務端與客戶端學習
一、項目概述
本項目基于Qt框架實現了TCP服務端與客戶端的基本通信,涵蓋連接、消息收發、斷開管理等功能,適合初學者系統學習Qt網絡模塊的實際用法。
二、項目結構
- 52/ 服務端:main.cpp、widget.cpp、widget.h
- 53/ 客戶端:main.cpp、widget.cpp、widget.h
三、環境配置
- Qt 5.x及以上
- 啟用network、widgets模塊
- C++11支持
四、服務端核心代碼詳解(52目錄)
1. main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}
2. widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{Q_OBJECT
public:Widget(QWidget *parent = nullptr);~Widget();
private:Ui::Widget *ui; // UI指針QTcpServer *tcpServer; // TCP服務端對象
private slots:void mNewConnetion(); // 新連接處理槽void receiveMessages(); // 接收消息槽void mStateChanged(QAbstractSocket::SocketState); // 連接狀態變化槽void on_pushButton_3_clicked(); // 發送消息按鈕槽void on_pushButton_clicked(); // 開始監聽按鈕槽void on_pushButton_2_clicked(); // 停止監聽按鈕槽
};
#endif // WIDGET_H
3. widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);tcpServer = new QTcpServer(this);this->setWindowTitle("服務端");connect(tcpServer, SIGNAL(newConnection()), this, SLOT(mNewConnetion()));ui->pushButton_2->setEnabled(false);
}
Widget::~Widget()
{delete ui;
}
void Widget::mNewConnetion()
{QTcpSocket *tmpTcpSocket = tcpServer->nextPendingConnection();QString ipaddr = tmpTcpSocket->peerAddress().toString();quint16 port = tmpTcpSocket->peerPort();ui->textBrowser->append("服務端:客戶端的ip地址:" + ipaddr);ui->textBrowser->append("服務端:客戶端的端口:" + QString::number(port));connect(tmpTcpSocket, SIGNAL(readyRead()), this, SLOT(receiveMessages()));connect(tmpTcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),this, SLOT(mStateChanged(QAbstractSocket::SocketState)));
}
void Widget::receiveMessages()
{QTcpSocket *tmpTcpSocket = (QTcpSocket *)sender();ui->textBrowser->append("客戶端:" + tmpTcpSocket->readAll());
}
void Widget::mStateChanged(QAbstractSocket::SocketState state)
{QTcpSocket *tmpTcpSocket = (QTcpSocket *)sender();switch (state) {case QAbstractSocket::UnconnectedState:ui->textBrowser->append("服務端:客戶端斷開連接");tmpTcpSocket->deleteLater();break;case QAbstractSocket::ConnectedState:ui->textBrowser->append("服務端:客戶端已連接");break;default:break;}
}
void Widget::on_pushButton_3_clicked()
{QList <QTcpSocket *> socketList = tcpServer->findChildren<QTcpSocket *>();qDebug() << "tcpSocket 數量:" << socketList.count() << endl;if (socketList.count() == 0) {ui->textBrowser->append("當前沒有客戶端連接,請先與客戶端連接!");return;}foreach (QTcpSocket *tmpTcpSocket, socketList) {tmpTcpSocket->write(ui->lineEdit->text().toUtf8());}ui->textBrowser->append("服務端:" + ui->lineEdit->text());
}
void Widget::on_pushButton_clicked()
{tcpServer->listen(QHostAddress("192.168.1.59"), 9999);ui->textBrowser->append("服務端:監聽的ip地址和端口:192.168.1.59,9999");ui->pushButton_2->setEnabled(true);ui->pushButton->setEnabled(false);
}
void Widget::on_pushButton_2_clicked()
{tcpServer->close();ui->pushButton->setEnabled(true);ui->pushButton_2->setEnabled(false);
}
五、客戶端核心代碼詳解(53目錄)
1. main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}
2. widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTcpSocket>
#include <QHostAddress>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{Q_OBJECT
public:Widget(QWidget *parent = nullptr);~Widget();
private:Ui::Widget *ui; // UI指針QTcpSocket *tcpSocket; // TCP客戶端對象
private slots:void receiveMessages(); // 接收消息槽void mStateChanged(QAbstractSocket::SocketState); // 連接狀態變化槽void on_pushButton_3_clicked(); // 發送消息按鈕槽void on_pushButton_clicked(); // 連接服務端按鈕槽void on_pushButton_2_clicked(); // 斷開連接按鈕槽
};
#endif // WIDGET_H
3. widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);this->setWindowTitle("客戶端");ui->pushButton_2->setEnabled(false);tcpSocket = new QTcpSocket(this);connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(receiveMessages()));connect(tcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(mStateChanged(QAbstractSocket::SocketState)));
}
Widget::~Widget()
{delete ui;
}
void Widget::receiveMessages()
{ui->textBrowser->append("服務端:" + tcpSocket->readAll());
}
void Widget::mStateChanged(QAbstractSocket::SocketState state)
{switch (state) {case QAbstractSocket::UnconnectedState:ui->textBrowser->append("客戶端:與服務端斷開連接");ui->pushButton->setEnabled(true);ui->pushButton_2->setEnabled(false);break;case QAbstractSocket::ConnectedState:ui->textBrowser->append("客戶端:已連接服務端");ui->pushButton->setEnabled(false);ui->pushButton_2->setEnabled(true);break;default:break;}
}
void Widget::on_pushButton_3_clicked()
{if (tcpSocket->state() == QAbstractSocket::ConnectedState) {tcpSocket->write(ui->lineEdit->text().toUtf8());ui->textBrowser->append("客戶端:" + ui->lineEdit->text());} elseui->textBrowser->append("請先與服務端連接!");
}
void Widget::on_pushButton_clicked()
{ui->textBrowser->append("客戶端:監聽的ip地址和端口:192.168.1.59,9999");tcpSocket->connectToHost(QHostAddress("192.168.1.59"), 9999);
}
void Widget::on_pushButton_2_clicked()
{tcpSocket->disconnectFromHost();
}