思维导图
基于QT的网络聊天室
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include<QTcpServer> //服务器类
#include<QTcpSocket> //客户端类
#include<QMessageBox> //对话框类
#include<QList> //链表容器
#include<QDebug> //信息调试类
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 read_slot(); //服务器将数据发送至客户端界面上的处理槽函数
private:
Ui::Widget *ui;
//声明一个服务器指针
QTcpServer *sever;
//定义存储客户端容器
QList<QTcpSocket*> socket_list;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//实例化服务器指针
sever = new QTcpServer(this);
}
Widget::~Widget()
{
delete ui;
}
//启动按钮对应的槽函数
void Widget::on_startBtn_clicked()
{
//获取ui界面上的端口信息
qint16 port = ui->portEdit->text().toUInt();
if(ui->startBtn->text() == "取消"){
QMessageBox::information(this,"","即将关闭客户端");
this->close();
}
//设置监听
if(sever->listen(QHostAddress::Any,port)){ //有客户端发起连接请求
QMessageBox::information(this,"","服务器已启动");
ui->startBtn->setText("取消");
}
connect(sever,&QTcpServer::newConnection,this,&Widget::newConnection_slot);
}
//服务器发出的newConnection信号对应的处理槽函数
void Widget::newConnection_slot(){
//获取最新连接的客户端套接字
//函数原型:virtual QTcpSocket *nextPendingConnection();
//功能:获取最新连接客户端的套接字
//参数:无
//返回值:套接字指针
QTcpSocket *s = sever->nextPendingConnection();
socket_list.push_back(s); //将s存入客户端容器中
//此时,客户端与服务器已经建立起来连接
//如果有客户端向服务器发来数据,那么该客户端会自动发射一个readyRead信号
//我们可以在该信号对应的槽函数中,读取客户端中的数据
connect(s,&QTcpSocket::readyRead,this,&Widget::read_slot);
}
void Widget::read_slot()
{
//判断当前客户端是否在连接中
for (int i = 0;i < socket_list.count();i++) {
//socketList.at(i)->state(); //任意一个客户端的状态
//函数原型:SocketState state() const;
//功能:返回套接字的状态
//参数:无
//返回值:套接字状态,是个枚举值,如果为0,表示无效连接
if(socket_list.at(i)->state() == 0){ //枚举值为0表示不在连接中
socket_list.removeAt(i); //从容器中删除
}
}
//判断客户端容器中是否有待读取的数据
for (int i = 0;i < socket_list.count();i++) {
//判断当前套接字是否有数据待读
//函数原型:qint64 bytesAvailable() const override;
//功能:求出当前套接字中待读数据的个数
//参数:无
//返回值:待读数据的个数
if(socket_list.at(i)->bytesAvailable() != 0){ //表明有数据待读取
//说明当前套接字中有数据
//读取当前套接字中的数据
//函数原型:QByteArray readAll();
//功能:读取套接字中的所有数据
//参数:无
//返回值:QByteArray读取下来的数据
QByteArray msg = socket_list.at(i)->readAll();
//将数据展示到ui界面---QString::fromLocal8Bit() <=> inet_ntoa( )
ui->listWidget->addItem(QString::fromLocal8Bit(msg));//-->字节序列(采用本地的8位编码)转换为字符序列
//将数据展示给用户
for (int j = 0;j < socket_list.count();j++) {
socket_list.at(j)->write(msg);
}
}
}
}
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}