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, "连接", "连接服务器成功!!!");}