qt网络聊天室
服务器:
配置文件.pro
- QT += core gui network
-
- greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
-
- CONFIG += c++11
-
- # The following define makes your compiler emit warnings if you use
- # any Qt feature that has been marked deprecated (the exact warnings
- # depend on your compiler). Please consult the documentation of the
- # deprecated API in order to know how to port your code away from it.
- DEFINES += QT_DEPRECATED_WARNINGS
-
- # You can also make your code fail to compile if it uses deprecated APIs.
- # In order to do so, uncomment the following line.
- # You can also select to disable deprecated APIs only up to a certain version of Qt.
- #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
-
- SOURCES += \
- main.cpp \
- widget.cpp
-
- HEADERS += \
- widget.h
-
- FORMS += \
- widget.ui
-
- # Default rules for deployment.
- qnx: target.path = /tmp/$${TARGET}/bin
- else: unix:!android: target.path = /opt/$${TARGET}/bin
- !isEmpty(target.path): INSTALLS += target
头文件
widget.h
- #ifndef WIDGET_H
- #define WIDGET_H
-
- #include
- #include
//服务器类头文件 - #include
//信息调试类 - #include
//消息对话框类头文件 - #include
//套接字类头文件 -
- QT_BEGIN_NAMESPACE
- namespace Ui { class Widget; }
- QT_END_NAMESPACE
-
- class Widget : public QWidget
- {
- Q_OBJECT
-
- public:
- Widget(QWidget *parent = nullptr);
- ~Widget();
-
-
- private slots:
- void on_startBtn_clicked();
- void newConnection_slot(); //自定义处理newConnection信号的函数
- void readyRead_slot(); //自定义处理readyRead信号的槽函数
-
- private:
- Ui::Widget *ui;
-
- //定义一个服务器指针
- QTcpServer *server;
-
- //定义一个客户端容器
- QList
clientList; - };
- #endif // WIDGET_H
源文件
main.cpp
- #include "widget.h"
-
- #include
-
- int main(int argc, char *argv[])
- {
- QApplication a(argc, argv);
- Widget w;
- w.show();
- return a.exec();
- }
widget.cpp
- //服务器
- //1、实例化服务器类对象,该对象就是服务器
- //2、服务器调用成员函数listen()将服务器设置为被动监听状态,监听时可以指定主机地址,也可以any监听所有的主机地址。 端口号若为0,则服务器自动分配,也可指定端口号
- //3、若有客户端连接,则服务器会发送一个newconnection信号,连接到对应的槽函数中处理相关逻辑
- //4、在处理connect信号的槽函数中,使用nextPendingConntiin获取最新连接的客户端套接字
- //5、将获取的套接字存入客户端容器中
- //6、若客户端有数据项向服务器发送,则客户端套接字会自动发射一个readyRead信号,来凝结到对应的槽函数中处理相关逻辑
- //7、在处理readyRead信号的槽函数中,来读取数据,
- //7-1、先循环遍历哪些套接字是无效的(断开连接的客户端),将其从客户端容器中删除,使用state函数判断状态,为0则是断开连接的,不为0不是断开的
- //7-2、在循环遍历判断是哪个客户端发来的数据,使用BytesAviable来判断哪个客户端有数据,为0则代表无
- //7-3、若有数据,使用read readLine readAll函数读取数据,
- //11、向套接字中写数据,可以使用write函数
-
-
- #include "widget.h"
- #include "ui_widget.h"
-
- Widget::Widget(QWidget *parent)
- : QWidget(parent)
- , ui(new Ui::Widget)
- {
- ui->setupUi(this);
-
- //给服务器实例化对象
- server = new QTcpServer(this); //该对象就是服务器,服务器创建完成
-
-
- }
-
- Widget::~Widget()
- {
- delete ui;
- }
-
-
- //启动服务器的槽函数
- void Widget::on_startBtn_clicked()
- {
- if(ui->portEdit->text().isEmpty())
- {
- QMessageBox::critical(this, "失败", "端口号不可为空");
- return;
- }
-
- //调用成员函数listen()将服务器设置为被动监听状态
- //函数原型:bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);
- //参数1:主机号,any监听所有的主机地址, 指定主机地址,监听指定的主机地址。
- //参数2:通过哪个端口号访问服务器,若为0,则服务器自由分配,若不为0,则指定要监听的端口号, quint16 是无符号的16位整型, short
- //返回值,成功返回真,失败返回假
-
- //获取端口号
- quint16 port = ui->portEdit->text().toUInt(); //toUInt(), 转为无符号整型
-
- if(!server->listen(QHostAddress::Any, port))
- {
- QMessageBox::critical(this, "失败", "服务器启动失败");
- return;
- }
- else
- {
- QMessageBox::information(this, "成功", "服务器启动成功");
- }
-
- //此时说明服务器启动成功,并对客户端进行监听
- //若有客户端发送连接请求,则服务器会自动发射一个newconnection信号
- //将给信号连接到对应的槽函数中
- connect(server, &QTcpServer::newConnection, this, &Widget::newConnection_slot);
- }
-
- //处理newConnection函数的槽函数的实现
- void Widget::newConnection_slot()
- {
-
- //循环遍历,从客户端套接字容器中删去已断开连接的客户端套接字
-
- //函数原型:SocketState state() const;
- //功能:判断套接字的状态
- //参数,无
- //返回值:返回套接字的状态(枚举, 0代表断开连接)
- for(int i = 0; i
count(); i++) - {
- if(0 == clientList.at(i)->state())
- {
- //移除下标为i的无效的客户端
- clientList.removeAt(i);
- }
- }
- //获取新连接的客户端的套接字
- //函数原型:virtual QTcpSocket *nextPendingConnection();
- //功能:获取新连接的客户端的套接字
- //无参,返回值就是获取到的客户端的套接字的指针
- QTcpSocket *s = server->nextPendingConnection();
-
- //将获取到的套接字存入到客户端套接字容器中
- clientList.push_back(s);
-
- //此时客户端和服务器建立连接
- //如果套接字有数据项发送给服务器时,该套接字自动发射一个readyRead信号
- //将readyRead信号连接到对应的槽函数中处理相关逻辑
- connect(s, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);
-
- }
-
- //自定义处理readyRead信号的槽函数的实现
- void Widget::readyRead_slot()
- {
- //遍历判断是哪个客户端套发来的数据
- //使用BytesAvalible函数,若无数据可读则为0
- for(int i=0; i
count(); i++) - {
- if(clientList[i]->bytesAvailable() != 0)
- {
- //读取套接字中的数据,可用read/readall/readline
- //函数原型QByteArray readAll();
- //功能:读取数据
- //无参,返回值,c风格的字符串
- QByteArray msg = clientList[i]->readAll();
-
- //将数据展示到ui界面上
- ui->msgList->addItem(QString::fromLocal8Bit(msg)); //将C风格的字符串转为QString类型的
-
- //将接收到的消息发送给所有的客户端
- for(int j=0; j
count(); j++) - {
- clientList[j]->write(msg);
- }
- }
- }
-
-
- }

客户端
配置文件.pro
- QT += core gui network
-
- greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
-
- CONFIG += c++11
-
- # The following define makes your compiler emit warnings if you use
- # any Qt feature that has been marked deprecated (the exact warnings
- # depend on your compiler). Please consult the documentation of the
- # deprecated API in order to know how to port your code away from it.
- DEFINES += QT_DEPRECATED_WARNINGS
-
- # You can also make your code fail to compile if it uses deprecated APIs.
- # In order to do so, uncomment the following line.
- # You can also select to disable deprecated APIs only up to a certain version of Qt.
- #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
-
- SOURCES += \
- main.cpp \
- widget.cpp
-
- HEADERS += \
- widget.h
-
- FORMS += \
- widget.ui
-
- # Default rules for deployment.
- qnx: target.path = /tmp/$${TARGET}/bin
- else: unix:!android: target.path = /opt/$${TARGET}/bin
- !isEmpty(target.path): INSTALLS += target
头文件
- #ifndef WIDGET_H
- #define WIDGET_H
-
- #include
- #include
//客户端头文件 - #include
//信息调试类头文件 - #include
//消息对话框类头文件 -
- QT_BEGIN_NAMESPACE
- namespace Ui { class Widget; }
- QT_END_NAMESPACE
-
- class Widget : public QWidget
- {
- Q_OBJECT
-
- public:
- Widget(QWidget *parent = nullptr);
- ~Widget();
-
- private slots:
- void on_connectBtn_clicked();
- void connected_slot(); //自定义处理connected信号的槽函数
- void readyRead_slot(); //自定义处理readyRead信号的槽函数
-
- void on_sendBtn_clicked();
-
- void on_disConnectBtn_clicked();
- void disconnected_slot(); //自定义处理disconnected信号的槽函数
-
- private:
- Ui::Widget *ui;
-
- //定义一个客户端指针
- QTcpSocket *client;
- };
- #endif // WIDGET_H
源文件
main.cpp
- #include "widget.h"
-
- #include
-
- int main(int argc, char *argv[])
- {
- QApplication a(argc, argv);
- Widget w;
- w.show();
- return a.exec();
- }
widget.cpp
- //客户端
- //1、实例化QTcpSocket类对象,该对象就是客户端
- //2、调用客户端对象的connecTtoHost的成员函数向服务器发送连接请求,需要给定服务器的ip和端口
- //3、如果与服务器连接成功,客户端自动发射一个connected信号,将信号与对应的槽函数进行连接处理相关逻辑即可
- //4、如果服务器有数据项向客户端发送,客户端会自动发射一个readyRead信号,将信号连接到对应的槽函数读取数据
- //5、若客户端要给服务器发送消息,使用write函数
- //6、在处理readyRead信号的槽函数中,使用read/readLine/readAll函数读取数据
- //7、使用该客户端对象的disconnectFromHost函数端口与服务器的连接,
- //8、如果成功断开则会自动发射disconnected信号,将disconnected信号与对应的槽函数连接处理即可
-
- #include "widget.h"
- #include "ui_widget.h"
-
-
- Widget::Widget(QWidget *parent)
- : QWidget(parent)
- , ui(new Ui::Widget)
- {
- ui->setupUi(this);
-
- //实例化客户端空间
- client = new QTcpSocket(this); //该对象就是客户端,创建客户端成功
-
- ui->sendBtn->setEnabled(false);
- ui->disConnectBtn->setEnabled(false);
-
- //若连接成功,则客户端自动发射一个connected信号
- //将connected信号连接到对应的槽函数处理相关逻辑
- //因为只需要连接一次,所以将其写到构造函数中
- connect(client, &QTcpSocket::connected, this, &Widget::connected_slot);
-
- //若服务器有数据项向客户端发送,客户端会自动发送readyRead信号
- //将readyRead信号与对应的槽函数连接
- //由于只需连接一次,所以写在构造函数中
- connect(client, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);
-
- //若断开成功,则客户端会自动发射一个disconnected信号
- //连接到对应的槽函数处理即可
- //因只需要连接一次,写在构造函数即可
- connect(client, &QTcpSocket::disconnected, this, &Widget::disconnected_slot);
- }
-
- Widget::~Widget()
- {
- delete ui;
- }
-
- //连接服务器按钮的槽函数
- void Widget::on_connectBtn_clicked()
- {
- if(ui->userNameEdit->text().isEmpty() || ui->ipEdit->text().isEmpty() || ui->portEdit->text().isEmpty())
- {
- QMessageBox::critical(this, "Error", "信息填写不完整");
- return;
- }
- //获取服务器的主机地址
- QString ip = ui->ipEdit->text();
- //获取服务器的端口号
- quint16 port = ui->portEdit->text().toUInt(); //toUInt()转化为无符号整数
- //该客户端对象调用成员函数连接服务器
- //函数原型:virtual void connectToHost(const QHostAddress &address, quint16 port, OpenMode mode = ReadWrite);
- //功能:客户端连接服务器
- //参数1:服务器的ip地址
- //参数2:客户端的端口号 , quint16 无符号的16位的整型 short
- //返回值:无
- client->connectToHost(ip, port);
-
- //顺便向客户端发送一条数据
- QString msg = ui->userNameEdit->text();
- msg = msg+ ": 进入聊天室";
-
- //使用write函数向服务器发送数据
- client->write(msg.toLocal8Bit()); // toLocal8Bit()转为C风格字符串
-
- //若连接成功,则客户端自动发射一个connected信号
- //将connected信号连接到对应的槽函数处理相关逻辑
- //因为只需要连接一次,所以将其写到构造函数中
- }
-
- //处理connected信号的槽函数的实现
- void Widget::connected_slot()
- {
- //说明连接成功
- ui->userNameEdit->setEnabled(false);
- ui->ipEdit->setEnabled(false);
- ui->portEdit->setEnabled(false);
- ui->connectBtn->setEnabled(false);
- ui->disConnectBtn->setEnabled(true);
- ui->sendBtn->setEnabled(true);
-
- //若服务器有数据项向客户端发送,客户端会自动发送readyRead信号
- //将readyRead信号与对应的槽函数连接
- //由于只需连接一次,所以写在构造函数中
-
- }
-
- //处理readyRead信号的槽函数
- void Widget::readyRead_slot()
- {
- //使用read/readLine/readAll读取数据
- QByteArray msg =client->readAll();
-
- //将读取的数据展示到ui界面上
-
- ui->msgList->addItem(QString::fromLocal8Bit(msg));
-
- }
-
- //发送按钮的槽函数
- void Widget::on_sendBtn_clicked()
- {
- //获取用户名
- QString userName = ui->userNameEdit->text();
- //获取文本输入框的内容
- QString msg = ui->textEdit->toPlainText();
-
- msg = userName + ": " + msg;
-
- //将数据发送给服务器
- client->write(msg.toLocal8Bit());
-
- //清空文本输入框
- ui->textEdit->clear();
-
- }
-
- //断开按钮对应的槽函数
- void Widget::on_disConnectBtn_clicked()
- {
- //告知服务器即将断开连接
- QString userName = ui->userNameEdit->text();
- QString msg = userName + ": 退出聊天室";
- client->write(msg.toLocal8Bit());
-
- //使用该类对象调用disconnectFromHost断开与服务器的连接
- //函数原型:virtual void disconnectFromHost();
- //无参 无返
- client->disconnectFromHost();
-
- //若断开成功,则客户端会自动发射一个disconnected信号
- //连接到对应的槽函数处理即可
- //因只需要连接一次,写在构造函数即可
- }
-
- void Widget::disconnected_slot()
- {
- ui->sendBtn->setEnabled(false);
- ui->disConnectBtn->setEnabled(false);
- ui->userNameEdit->setEnabled(true);
- ui->ipEdit->setEnabled(true);
- ui->portEdit->setEnabled(true);
- QMessageBox::information(this, "退出", "断开成功");
- }
ui界面

数据库:
配置文件.pro
- QT += core gui sql
-
- greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
-
- CONFIG += c++11
-
- # The following define makes your compiler emit warnings if you use
- # any Qt feature that has been marked deprecated (the exact warnings
- # depend on your compiler). Please consult the documentation of the
- # deprecated API in order to know how to port your code away from it.
- DEFINES += QT_DEPRECATED_WARNINGS
-
- # You can also make your code fail to compile if it uses deprecated APIs.
- # In order to do so, uncomment the following line.
- # You can also select to disable deprecated APIs only up to a certain version of Qt.
- #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
-
- SOURCES += \
- main.cpp \
- widget.cpp
-
- HEADERS += \
- widget.h
-
- FORMS += \
- widget.ui
-
- # Default rules for deployment.
- qnx: target.path = /tmp/$${TARGET}/bin
- else: unix:!android: target.path = /opt/$${TARGET}/bin
- !isEmpty(target.path): INSTALLS += target
头文件
- #ifndef WIDGET_H
- #define WIDGET_H
-
- #include
- #include
//数据库管理类 - #include
//执行sql语句对应的类 - #include
//记录类 - #include
//消息对话框类 - #include
//信息调试类 -
- QT_BEGIN_NAMESPACE
- namespace Ui { class Widget; }
- QT_END_NAMESPACE
-
- class Widget : public QWidget
- {
- Q_OBJECT
-
- public:
- Widget(QWidget *parent = nullptr);
- ~Widget();
-
- private slots:
- void on_inputBtn_clicked();
-
- void on_showBtn_clicked();
-
- void on_searchBtn_clicked();
-
- void on_deleteBtn_clicked();
-
- private:
- Ui::Widget *ui;
-
- //定义一个数据库对象
- QSqlDatabase db;
- };
- #endif // WIDGET_H
源文件:
main.cpp
- #include "widget.h"
-
- #include
-
- int main(int argc, char *argv[])
- {
- QApplication a(argc, argv);
- Widget w;
- w.show();
- return a.exec();
- }
widget.cpp
- #include "widget.h"
- #include "ui_widget.h"
-
- Widget::Widget(QWidget *parent)
- : QWidget(parent)
- , ui(new Ui::Widget)
- {
- ui->setupUi(this);
-
- //判断数据库对象是否包含了自己使用的数据库,Student.db
- if(!db.contains("Student.db"))
- {
- //添加数据库
- // static QSqlDatabase addDatabase(QSqlDriver* driver, const QString& connectionName = QLatin1String(defaultConnection));
- //参数1:数据库的版本
- //返回值:添加的数据库
- db = QSqlDatabase::addDatabase("QSQLITE"); //表明使用的是Sqlite3版本的数据库
-
- //给数据库命名
- db.setDatabaseName("Student.db");
- }
-
- //打开数据库
- if(!db.open())
- {
- QMessageBox::information(this, "提示", "数据库打开失败");
- }
-
- //此时说明数据库已经创建出来并打开了,就可以创建数据表了
- //创建数据表需要使用sql语句, 需要使用QSQLQuerry对象来完成
- //准备sql语句
- // QString sql = "create table if not exists myTable("
- // "id integer Primary key autoincrement,"
- // "numb integer,"
- // "name varchar(10),"
- // "sex varchar(4))";
- QString sql = "create table if not exists myTable(" //创建表的sql语句
- "id integer primary key autoincrement," //id主键,允许自增
- "numb integer," //学号,是整形
- "name varchar(10)," //姓名 字符串
- "score integer,"
- "sex varchar(4))"; //性别 字符串
-
-
- //定义语句执行者
- QSqlQuery queery;
- //使用querry调用成员函数exec执行sql语句
- if(!queery.exec(sql))
- {
- QMessageBox::information(this, "失败", "表格创建失败");
- return;
- }
- else
- {
- QMessageBox::information(this, "成功", "表格创建出成功");
- }
- }
-
- Widget::~Widget()
- {
- delete ui;
- }
-
- //录入按钮对应的槽函数
- void Widget::on_inputBtn_clicked()
- {
- //获取ui界面中要存入数据库中的数据
- int numb_ui = ui->numEdit->text().toUInt(); //获取ui界面的学号
- QString name_ui = ui->nameEdit_2->text(); //获取ui界面的姓名
- int score_ui = ui->scoreEdit_3->text().toUInt(); //获取ui界面上的成绩
- QString sex_ui = ui->sexEdit_4->text(); //获取ui界面上的性别
-
- //判断是否有漏填数据
- if(numb_ui == 0 || name_ui.isEmpty() || score_ui == 0 || sex_ui.isEmpty())
- {
- QMessageBox::information(this, "提示", "请将数据填写完整");
- return;
- }
-
- //准备sql语句
- QString sql = QString("insert into myTable(numb, name, score, sex)"
- "values(%1, '%2', %3, '%4')")
- .arg(numb_ui).arg(name_ui).arg(score_ui).arg(sex_ui);
- qDebug() << sql;
-
- //定义语句执行者
- QSqlQuery querry;
- //调用执行者的exec()函数执行sql语句
- if(!querry.exec(sql))
- {
- QMessageBox::information(this, "失败", "数据插入失败");
- }
- else
- {
- QMessageBox::information(this, "成功", "数据录入成功");
- }
-
- }
-
- //展示按钮对应的槽函数
- void Widget::on_showBtn_clicked()
- {
- QString sql = "select * from MyTable";
-
- //定义语句执行者
- QSqlQuery querry;
-
- //调用执行者的exec()函数执行sql语句
- if(!querry.exec(sql))
- {
- QMessageBox::information(this, "失败", "查询失败");
- return;
- }
- else
- {
- QMessageBox::information(this, "成功", "查询成功");
- }
-
- //此时,将查找到的所有结果。全部都放在querry中了
- //可以通过next函数不断遍历查询结果
- int i = 0; //记录行号
- while(querry.next())
- {
- //遍历的就是任意一组记录querry.record
- //qDebug() << querry.record();
-
- //querry.record().count(); 返回当前记录对应数据项的个数
- //querry.record().count();
-
- //要找到每条记录中的每个数据
- //qDebug() << querry.record().value(2);
- //querry.record().value(j).toString() //将记录的某一项的转为字符串
-
- //将数据库中的表格展示到ui界面
- for(int j = 0; j
record().count()-1; j++) - {
- ui->tableWidget->setItem(i, j, new QTableWidgetItem(querry.record().value(j+1).toString()));
- }
- i++; //进行下一行
- }
- }
-
-
- void Widget::on_searchBtn_clicked()
- {
- //获取学号
- QString name_ui = ui->nameEdit_2->text();
- int numb_ui = ui->numEdit->text().toUInt();
-
- //sql语句
- QString sql = QString("select * from myTable where numb = %1").arg(numb_ui);
-
- //定义语句执行者
- QSqlQuery querry;
-
- //执行者使用exec函数执行sql语句
- if(!querry.exec(sql))
- {
- QMessageBox::information(this , "提示", "查询失败");
- return;
- }
- else
- {
- QMessageBox::information(this , "提示", "查询成功");
- }
-
- int i = 0; //行号
- while(querry.next())
- {
- for(int j=0; j
record().count()-1; j++) - {
- ui->tableWidget->setItem(i, j, new QTableWidgetItem(querry.record().value(j+1).toString()));
- }
- }
- }
-
- void Widget::on_deleteBtn_clicked()
- {
- QString name_ui = ui->nameEdit_2->text();
- //sql语句
- QString sql = QString("delete from myTable where name = '%1'").arg(name_ui);
- qDebug() << sql;
- //定义语句执行者
- QSqlQuery querry;
-
- //querry调用自己成员函数执行sql语句
- if(!querry.exec(sql))
- {
- QMessageBox::information(this, "提示", "删除失败");
- return;
- }
- else
- {
- QMessageBox::information(this, "提示", "删除成功");
- }
-
-
- }
ui界面
