网络聊天室

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布局:

相关推荐
rannn_1111 小时前
【MySQL学习|黑马笔记|Day7】触发器和锁(全局锁、表级锁、行级锁、)
笔记·后端·学习·mysql
喜欢吃燃面2 小时前
C++算法竞赛:位运算
开发语言·c++·学习·算法
传奇开心果编程2 小时前
【传奇开心果系列】Flet框架实现的家庭记账本示例自定义模板
python·学习·ui·前端框架·自动化
_Kayo_8 小时前
node.js 学习笔记3 HTTP
笔记·学习
CCCC131016311 小时前
嵌入式学习(day 28)线程
jvm·学习
星星火柴93612 小时前
关于“双指针法“的总结
数据结构·c++·笔记·学习·算法
小狗爱吃黄桃罐头12 小时前
正点原子【第四期】Linux之驱动开发篇学习笔记-1.1 Linux驱动开发与裸机开发的区别
linux·驱动开发·学习
艾莉丝努力练剑13 小时前
【洛谷刷题】用C语言和C++做一些入门题,练习洛谷IDE模式:分支机构(一)
c语言·开发语言·数据结构·c++·学习·算法
武昌库里写JAVA14 小时前
JAVA面试汇总(四)JVM(一)
java·vue.js·spring boot·sql·学习
杜子不疼.14 小时前
《Python学习之字典(一):基础操作与核心用法》
开发语言·python·学习