网络聊天室

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

相关推荐
朝九晚五ฺ7 小时前
【Linux探索学习】第十四弹——进程优先级:深入理解操作系统中的进程优先级
linux·运维·学习
猫爪笔记9 小时前
前端:HTML (学习笔记)【1】
前端·笔记·学习·html
pq113_69 小时前
ftdi_sio应用学习笔记 3 - GPIO
笔记·学习·ftdi_sio
澄澈i9 小时前
设计模式学习[8]---原型模式
学习·设计模式·原型模式
爱米的前端小笔记10 小时前
前端八股自学笔记分享—页面布局(二)
前端·笔记·学习·面试·求职招聘
alikami10 小时前
【前端】前端学习
学习
一只小菜鸡..11 小时前
241118学习日志——[CSDIY] [ByteDance] 后端训练营 [06]
学习
Hacker_Oldv12 小时前
网络安全的学习路线
学习·安全·web安全
蒟蒻的贤12 小时前
vue学习11.21
javascript·vue.js·学习
高 朗12 小时前
【GO基础学习】基础语法(2)切片slice
开发语言·学习·golang·slice