一、思维导图
二、优化聊天室代码
服务器 头文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTcpServer>
#include <QMessageBox>
#include <QTcpSocket>
#include <QList>
#include <QNetworkInterface>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
public slots:
void newConnection_slot();
void readyRead_slot();
private slots:
void on_startBtn_clicked();
private:
Ui::Widget *ui;
QTcpServer *server; //实例化服务器对象
QList<QTcpSocket *> socketList; //定义容器存放客户端
};
#endif // WIDGET_H
服务器源文件
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
, server(new QTcpServer(this))
{
ui->setupUi(this);
QString ip_address;
QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses(); //获取所有ip
for(int i = 0; i < ipAddressesList.size(); i++){
QHostAddress ipAddr = ipAddressesList.at(i);
if(ipAddr.protocol() == QAbstractSocket::IPv4Protocol){ //筛选ipv4
if(!ipAddr.toString().startsWith("169")){ //过滤网卡、路由器ip
ip_address = ipAddr.toString();
break;
}
}
}
if(ip_address.isEmpty()){
ip_address = QHostAddress(QHostAddress::LocalHost).toString();
}
ui->ipNetLab->setText(ip_address);
}
Widget::~Widget()
{
delete ui;
}
void Widget::newConnection_slot()
{
//newConnection信号对应槽函数
//获取套接字
QTcpSocket *s = server->nextPendingConnection();
socketList.push_back(s); //尾插
connect(s, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);
}
void Widget::readyRead_slot()
{
//readyRead信号对应槽函数
//读取数据
for(int i = 0; i < socketList.count(); i++){
if(socketList.at(i)->state() == 0){
//移除无效客户端
socketList.removeAt(i);
}
}
for(int i = 0; i < socketList.count(); i++){
if(socketList.at(i)->bytesAvailable() != 0){
//读取有待读数据
QByteArray msg = socketList.at(i)->readAll();
ui->listWidget->addItem(QString::fromLocal8Bit(msg));
//广播给所有客户端
for(int j = 0; j < socketList.count(); j++){
socketList.at(j)->write(msg);
}
}
}
}
void Widget::on_startBtn_clicked()
{
//启动
//获取端口号
quint16 port = ui->portEdit->text().toUInt();
//设置监听
if(server->listen(QHostAddress::Any, port)){
QMessageBox::information(this, "", "启动服务器成功");
} else {
QMessageBox::warning(this, "", "启动服务器失败");
return;
}
connect(server, &QTcpServer::newConnection, this, &Widget::newConnection_slot);
}
客户端头文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTcpSocket>
#include <QMessageBox>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public slots:
void connected_slot(); //connected()信号
void readyRead_slot(); //readyRead()信号
void disconnected_slot(); //disconnected()信号
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_connectBtn_clicked();
void on_sendBtn_clicked();
void on_disconnectBtn_clicked();
private:
Ui::Widget *ui;
QTcpSocket *socket; //实例化一个客户端指针对象
QString userName; //定义一个存储用户信息的变量
};
#endif // WIDGET_H
客户端源文件
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
, socket(new QTcpSocket(this))
{
ui->setupUi(this);
//初始化界面
ui->msgEdit->setEnabled(false);
ui->sendBtn->setEnabled(false);
ui->disconnectBtn->setEnabled(false);
//客户端连接服务器
connect(socket, &QTcpSocket::connected, this, &Widget::connected_slot);
//接收数据
connect(socket, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);
//断开连接
connect(socket, &QTcpSocket::disconnected, this, &Widget::disconnected_slot);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_connectBtn_clicked()
{
//连接按钮对应槽函数
//获取ip和port
QString ip = ui->ipEdit->text();
quint16 port = ui->portEdit->text().toUInt();
//客户端连接服务器
socket->connectToHost(ip, port);
}
void Widget::connected_slot()
{
userName = ui->userNameEdit->text();
QString msg = userName + " 进入聊天室";
//将信息发送到服务器
socket->write(msg.toLocal8Bit());
//连接服务器成功
QMessageBox::information(this, "提示", "链接服务器成功", QMessageBox::Ok);
//组件可用的相关设置
ui->msgEdit->setEnabled(true);
ui->sendBtn->setEnabled(true);
ui->disconnectBtn->setEnabled(true);
ui->userNameEdit->setEnabled(false);
ui->ipEdit->setEnabled(false);
ui->portEdit->setEnabled(false);
ui->connectBtn->setEnabled(false);
}
void Widget::readyRead_slot()
{
//读取服务器发来的数据
QByteArray msg = socket->readAll();
QString s = QString::fromLocal8Bit(msg);
//截取用户名
QString user_Name = s.mid(0, userName.size());
if(user_Name == userName)
{
if(s.mid(userName.size(), 1) == " ")
{
QListWidgetItem *item = new QListWidgetItem(s);
item->setTextAlignment(Qt::AlignCenter);
ui->listWidget->addItem(item);
}
else{
//如果是本机用户则右对齐
QListWidgetItem *item = new QListWidgetItem(s);
item->setTextAlignment(Qt::AlignRight);
ui->listWidget->addItem(item);
}
}
else
{
//将数据放入ui界面上
ui->listWidget->addItem(QString::fromLocal8Bit(msg));
}
}
void Widget::disconnected_slot()
{
//组件可用的相关设置
ui->msgEdit->setEnabled(false);
ui->sendBtn->setEnabled(false);
ui->disconnectBtn->setEnabled(false);
ui->userNameEdit->setEnabled(true);
ui->ipEdit->setEnabled(true);
ui->portEdit->setEnabled(true);
ui->connectBtn->setEnabled(true);
}
void Widget::on_disconnectBtn_clicked()
{
//发送断开信息给服务器
QString msg = userName + " 离开聊天室";
//发送给服务器
socket->write(msg.toLocal8Bit());
//断开与服务器的连接
socket->disconnectFromHost();
}
void Widget::on_sendBtn_clicked()
{
//获取ui界面的信息
QString msg = ui->msgEdit->toPlainText();
msg = userName + ": " + msg;
//发送给服务器
socket->write(msg.toLocal8Bit());
//清空编辑器
ui->msgEdit->clear();
}