1、思維導圖
?2、TCp
服務器
?
#ifndef MYWIDGET_H#define MYWIDGET_H#include <QWidget>#include <QTcpServer>#include <QList>#include <QTcpSocket>#include <QMessageBox>#include <QDebug>#include <QTcpServer>QT_BEGIN_NAMESPACEnamespace Ui { class MyWidget; }QT_END_NAMESPACEclass MyWidget : public QWidget{Q_OBJECTpublic:MyWidget(QWidget *parent = nullptr);~MyWidget();private slots://void on_pButton_clicked();void on_startbtn_clicked();void newConnect_slot();void readyRead_slot();private:Ui::MyWidget *ui;QTcpServer *ser;QList<QTcpSocket *> cliList; //客戶端容器鏈表};#endif // MYWIDGET_H
#include "mywidget.h"#include "ui_mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent), ui(new Ui::MyWidget){ui->setupUi(this);//1、給服務器指針實例化對象ser = new QTcpServer(this);}MyWidget::~MyWidget(){delete ui;}//啟動按鈕對應的槽函數void MyWidget::on_startbtn_clicked(){if(ui->startbtn->text() == "啟動"){//獲取ui界面上的端口號quint16 port = ui->portEdit->text().toUInt();//啟動服務器//2、將服務器設置成被動監聽狀態if(ser->listen(QHostAddress::Any, port) == true)//參數1:監聽的ip地址,如果設置成Any,表示監聽所有類型的主機地址,也可以指定特定的主機地址進行監聽//參數2:端口號,如果設置為0,則讓系統自動分配一個端口號,如果使用具體的端口號,則需要指定{QMessageBox::information(this, "成功", "服務器啟動成功");}else{QMessageBox::information(this, "成功", "服務器啟動失敗");}//當啟動服務器后,如果有客戶端發來連接請求,那么該服務器就會自動發射一個newConnection信號//我們可以將該信號,連接到對應的槽函數中處理相關邏輯connect(ser, &QTcpServer::newConnection, this, &MyWidget::newConnect_slot);//將文本內容更改成 關閉ui->startbtn->setText("關閉");}else{//關閉服務器ser->close(); //關閉監聽//將文件內容更改成 啟動ui->startbtn->setText("啟動");}}//處理nYvoid MyWidget::newConnect_slot(){qDebug () <<"有新客戶端發來連接請求了,請盡快處理";//獲取最新連接的客戶端套接字,并將最新連接的套接字地址返回QTcpSocket* socket = ser->nextPendingConnection();//將該客戶端套接字放入到客戶端容器中cliList.append(socket);//當有客戶端向服務器發來數據時,當前這個客戶端套接字就會自動發射一個readyRead信號//我們可以將該信號連接到對應的信號處理函數中,處理相關數據connect(socket, &QTcpSocket::readyRead, this, &MyWidget::readyRead_slot);}//關于readyRead信號對應的槽函數的定義void MyWidget::readyRead_slot(){//判斷客戶端容器中,是否有已經退出的客戶端,或無效的客戶端,如果有,將其進行移除for(int i=0; i<cliList.length(); i++){if(cliList[i]->state() == QTcpSocket::UnconnectedState){//功能:判斷當前套接字的狀態//參數:無//返回值:readyRead_slot表示無效的套接字cliList.removeAt(i); //將下標為i的客戶端套接字從容器中移除}}//再將客戶端容器遍歷一遍,判斷哪個客戶端中有數據待讀for(int i=0; i<cliList.length(); i++){if(cliList[i]->bytesAvailable() != 0){//功能:獲取當前套接字中待讀數據的個數//參數:無//返回值:返回套接字中待讀數據的個數,如果為0,表示沒有數據可讀//如果不等于0,表示有數據可讀,可以使用readAll讀取數據QByteArray msg = cliList[i]->readAll();//將該消息,展示到ui界面上ui->msgWidget->addItem(QString::fromLocal8Bit(msg));//將該消息轉發給所有客戶端for(int j=0; j<cliList.length(); j++){if(i!=j) //不轉發給自己{cliList[j]->write(msg);}}}}}
?客戶端
?
#ifndef MYWIDGET_H#define MYWIDGET_H#include <QWidget>#include <QTcpSocket>#include <QMessageBox>QT_BEGIN_NAMESPACEnamespace Ui { class MyWidget; }QT_END_NAMESPACEclass MyWidget : public QWidget{Q_OBJECTpublic:MyWidget(QWidget *parent = nullptr);~MyWidget();private slots:void on_pushButton_clicked();void connnected_slot();void readyRead_slot();private:Ui::MyWidget *ui;QTcpSocket *cli; //定義客戶端指針QString userName; //用戶名};#endif // MYWIDGET_H
?
#include "mywidget.h"#include "ui_mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent), ui(new Ui::MyWidget){ui->setupUi(this);//實例化一個客戶端對象cli = new QTcpSocket(this);connect(cli,&QTcpSocket::connected,this,&MyWidget::connnected_slot);connect(cli,&QTcpSocket::readyRead,this,&MyWidget::readyRead_slot);//將客戶端的connected信號連接到自定義的槽函數中connect(cli, &QTcpSocket::connected, this, &MyWidget::connnected_slot);}MyWidget::~MyWidget(){delete ui;}//連接服務器按鈕對應的槽函數void MyWidget::on_pushButton_clicked(){if(ui->intobtn->text() == "連接服務器"){//執行連接服務器的工作//獲取ui界面上的數據userName = ui->userNameEdit->text(); //用戶名QString ip = ui->ipEdit_2->text(); //ip地址quint16 port = ui->portEdit->text().toUInt(); //端口號//向服務器發送連接請求cli->connectToHost(ip, port);//功能:向指定的服務器發送連接請求//參數1:服務器ip地址//參數2:服務器端口號//當成功連接服務器后,當前客戶端會自動發射一個connected的信號,我們可以將該信號連接到對應的槽函數中處理邏輯//由于該操作只需進行一次即可,所以寫在構造函數中即可//將按鈕內容更成 斷開服務器ui->intobtn->setText("斷開服務器");}else{QString msg = userName+":離開聊天室";cli->write(msg.toLocal8Bit());//執行斷開服務器工作cli->disconnectFromHost();//將按鈕內容更改成 連接服務器ui->intobtn->setText("連接服務器");}}//處理readyRead信號對應的槽函數的是實現void MyWidget::readyRead_slot(){QByteArray msg =cli->readAll();ui->msgWidget->addItem(QString::fromLocal8Bit(msg));}//自定義處理connnected信號的槽函數的實現void MyWidget::connnected_slot(){QMessageBox::information(this, "連接", "連接服務器成功!!!");}
?