网络聊天室

QT网络聊天室服务器实现(TCP)

widget.h文件:

cpp 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer> //服务器类
#include <QMessageBox> //消息对话框类
#include <QTcpSocket> //客户端类
#include <QList> //链表容器类

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_btn_start_clicked();

public slots:
    void newConnection_slot();//newConnection信号对应的槽函数
    void readyRead_slot();

private:
    Ui::Widget *ui;

    //实例化一个服务器指针
    QTcpServer *sever;

    //定义一个存放客户端套接字的容器
    QList<QTcpSocket *> socketList;
};
#endif // WIDGET_H

widget.cpp文件:

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
    , sever(new QTcpServer(this))   //给服务器指针实例空间
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}


//启动服务器按钮对应的槽函数
void Widget::on_btn_start_clicked()
{
    //获取ui界面上的端口号
    quint16 port = ui->portEdit->text().toUInt();//将字符串转换成整型

    //让服务器设置监听
    //判断监听是否成功
    if(sever->listen(QHostAddress::Any, port))
    {
        QMessageBox::information(this,"","启动服务器成功");
    }else {
        QMessageBox::information(this,"","启动服务器失败");
        return;
    }

    //此时服务器已经设置好监听,如果有客户端发来连接,那么服务器段就会自动发射一个newConnection()信号
    //将该信号连接到自定义的槽函数
    connect(sever, &QTcpServer::newConnection, this, &Widget::newConnection_slot);
}


void Widget::newConnection_slot()
{
    //使用nextPaddingConnectio()  获取最新连接客户端的套接字
    QTcpSocket *s = sever->nextPendingConnection();

    //将客户端放入容器中
    socketList.push_back(s);

    //程序运行至此,此时说明服务器和客户端已经建立连接
    //如果客户端向服务器发来数据,客户端就会自动发射一个 readyRead 信号
    connect(s, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);
}

void Widget::readyRead_slot()
{
    //遍历客户端容器,移除无效客户端
    for(int i=0; i<socketList.count(); i++)//count()就是容器的元素个数
    {
        //state()函数功能:判断连接状态
        if(socketList.at(i)->state() == 0)
        {
            //删除该元素
            socketList.removeAt(i);
        }
    }

    //遍历客户端容器,寻找哪个客户端有数据待读
    for(int i=0; i<socketList.count(); i++)
    {
        //bytesAvailable()函数功能:数据的字节
        if(socketList.at(i)->bytesAvailable() != 0)//说明有数据
        {
            //读取数据
            QByteArray msg = socketList.at(i)->readAll();

            //将读取到的数据  放入ui界面上
            ui->listWidget->addItem(QString::fromLocal8Bit(msg));

            //将数据广播给所有客户端
            for(int j=0; j<socketList.count(); j++)
            {
                socketList.at(j)->write(msg);
            }
        }
    }
}

main.c文件:

cpp 复制代码
#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

服务器端ui布局:

QT网络聊天室客户端实现(TCP)

widget.h文件:

cpp 复制代码
#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:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_connectBtn_clicked();

    void on_sendBtn_clicked();

    void on_disconnectBtn_clicked();

public slots:
    void connected_slot();//
    void readyRead_slot();//readyRead() 信号对应槽函数声明
    void disconnected_slot();//disconnected() 信号对应槽函数声明

private:
    Ui::Widget *ui;

    //实例化一个客户端指针
    QTcpSocket *socket;

    //定义一个变量存储用户名
    QString userName;
};
#endif // WIDGET_H

widget.cpp文件:

cpp 复制代码
#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);

    //如果成功连接服务器,那么客户端就会自动发射一个 connected() 信号
    //将该信号连接到自定义的槽函数,由于只需要连接一次,所以连接函数写在构造函数中
    connect(socket, &QTcpSocket::connected, this, &Widget::connected_slot);

    //此时说明客户端和服务器已经成功建立连接,如果服务器发来数据,那么客户端就会自动发射 readyRead() 信号
    //将该信号连接到自定义的槽函数中,读取数据。由于只需要连接一次,所以连接函数写在构造函数中
    connect(socket, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);

    //如果成功与服务器断开连接,那么客户端就会自动发射 disconnected() 信号
    //将信号连接到自定义的槽函数中处理逻辑代码,由于只需连接一次,所以连接函数写在构造函数中
    connect(socket, &QTcpSocket::disconnected, this, &Widget::disconnected_slot);
}

Widget::~Widget()
{
    delete ui;
}


//连接服务器按钮对应的槽函数
void Widget::on_connectBtn_clicked()
{
    //获取ui界面上的 ip 和 端口号
    QString ip = ui->ipEdit->text();
    quint16 port = ui->portEdit->text().toUInt();//将字符串转换整型

    //让客户端连接服务器
    socket->connectToHost(ip, port);



}

//connected 信号对应的槽函数实现
void Widget::connected_slot()
{
    QMessageBox::information(this, "", "连接服务器成功");

    //告诉服务器  我来了
    userName = ui->userNameEdit->text();
    //组织语言
    QString msg = userName + ": 进入聊天室";
    //将信息发送给服务器
    socket->write(msg.toLocal8Bit());


    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);

}

//readyRead() 信号对应槽函数实现
void Widget::readyRead_slot()
{
    //读取服务器发来的数据
    QByteArray msg = socket->readAll();

    //将信息放入 ui 界面上
    ui->listWidget->addItem(QString::fromLocal8Bit(msg));
}

//disconnected() 信号对应槽函数实现
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_sendBtn_clicked()
{
    //获取ui界面上的内容
    QString msg = ui->msgEdit->text();

    msg = userName + ": " + msg;

    //将信息发送给服务器
    socket->write(msg.toLocal8Bit());

    //清空
    ui->msgEdit->clear();
}


//断开连接按钮  对应的槽函数
void Widget::on_disconnectBtn_clicked()
{
    //告诉服务器  我走了
    QString msg = userName + ": 离开聊天室";

    socket->write(msg.toLocal8Bit());

    //将客户端于服务器断开连接
    socket->disconnectFromHost();

}

main.cpp文件:

cpp 复制代码
#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

客户端ui布局:

相关推荐
@小博的博客1 小时前
C++初阶学习第十弹——深入讲解vector的迭代器失效
数据结构·c++·学习
南宫生2 小时前
贪心算法习题其四【力扣】【算法学习day.21】
学习·算法·leetcode·链表·贪心算法
懒惰才能让科技进步3 小时前
从零学习大模型(十二)-----基于梯度的重要性剪枝(Gradient-based Pruning)
人工智能·深度学习·学习·算法·chatgpt·transformer·剪枝
love_and_hope3 小时前
Pytorch学习--神经网络--搭建小实战(手撕CIFAR 10 model structure)和 Sequential 的使用
人工智能·pytorch·python·深度学习·学习
Chef_Chen3 小时前
从0开始学习机器学习--Day14--如何优化神经网络的代价函数
神经网络·学习·机器学习
芊寻(嵌入式)3 小时前
C转C++学习笔记--基础知识摘录总结
开发语言·c++·笔记·学习
hong1616884 小时前
跨模态对齐与跨领域学习
学习
阿伟来咯~4 小时前
记录学习react的一些内容
javascript·学习·react.js
Suckerbin5 小时前
Hms?: 1渗透测试
学习·安全·网络安全
水豚AI课代表5 小时前
分析报告、调研报告、工作方案等的提示词
大数据·人工智能·学习·chatgpt·aigc