QT学习day5(QT实现TCP协议)

news/2024/7/5 3:05:46

作业:利用TCP客户端和服务器实现网络聊天室(简单版QQ)

1.服务器代码

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include<QTcpServer>            //服务器头文件
#include<QTcpSocket>             //客户端头文件
#include<QList>                  //链表容器
#include<QMessageBox>            //消息对话框
#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 readyRead_slot();              //自定义处理readyRead信号的槽函数的声明


    
private:
    Ui::Widget *ui;
    //实例化服务对象
    QTcpServer *server;//实例化一个服务器对象
    //创一个存放客户端的套接字的容器
    QList<QTcpSocket *> clientList;
};
#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);

    //给客户端实例化空间
    socket = new QTcpSocket(this);


    //初始化界面(设置不可用)
    ui->msgEdit->setEnabled(false);
    ui->setBtn->setEnabled(false);
    ui->disBtn->setEnabled(false);


    //判断是否连接成功,如果连接成功客户端会自动发射connected,将该信号连接到自定义的槽函数中处理相关的逻辑
    //因为只需要连接一次,所以我们将连接函数写在构造函数中
    connect(socket,&QTcpSocket::connected,this,&Widget::connected_slot);//定义在构造函数是为了只连接一次


    //此时说明服务器和客户端此时已经建立好连接,如果服务器发来数据,该客户端会自动发射readRead信号
    connect(socket,&QTcpSocket::readyRead,this,&Widget::readyRead_slot);

      //判断是否断开成功,如果成功断开连接,客户端自动发射disconnect信号
    connect(socket,&QTcpSocket::disconnected,this,&Widget::dis_slot);

}

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

//链接服务器按钮对应的槽函数
void Widget::on_connectStn_clicked()
{

    //获取ui界面上的IP和端口号
    uesrName=ui->usrnameEdit->text();
    QString ip= ui->ipEdit->text();
    quint16 port=ui->portEdit->text().toUInt();//转换成整型
    //客户端连接链接服务器
    socket->connectToHost(ip,port);




}
//连接成功对应的槽函数实现
void Widget::connected_slot()
{
    //告诉服务器 我来了
    QString msg = uesrName + ":进入聊天室";
    //将信息发送给服务器
    socket ->write(msg.toLocal8Bit());



    //将ui界面上的控价进行相关设置

    ui->usrnameEdit->setEnabled(false);
    ui->ipEdit->setEnabled(false);
    ui->portEdit->setEnabled(false);
    ui->connectStn->setEnabled(false);



    ui->msgEdit->setEnabled(true);
    ui->setBtn->setEnabled(true);
    ui->disBtn->setEnabled(true);


}
void Widget::readyRead_slot()//readyread对应的槽函数
{
    //说明服务器给客户端发来数据
    QByteArray msg = socket->readAll();
    //将数据放入到ui界面中
    ui->listWidget->addItem(QString::fromLocal8Bit(msg));

}

void Widget::dis_slot()
{
    ui->usrnameEdit->setEnabled(true);
    ui->ipEdit->setEnabled(true);
    ui->portEdit->setEnabled(true);
    ui->connectStn->setEnabled(true);



    ui->msgEdit->setEnabled(false);
    ui->setBtn->setEnabled(false);
    ui->disBtn->setEnabled(false);

}


void Widget::on_setBtn_clicked()//发送按钮对应的槽函数处理
{
    //获取ui界面上的文本内容
    QString msg =uesrName+":"+ ui->msgEdit->text();
    //将信息发送给服务器
    socket->write(msg.toLocal8Bit());

    //将msg的文本清空
    ui->msgEdit->clear();

}

void Widget::on_disBtn_clicked()//断开按钮对应的槽函数处理
{
   QString msg = uesrName+":"+ "离开了聊天室,尔等也退下吧";
   socket->write(msg.toLocal8Bit());

   socket->disconnectFromHost();


}






服务器 ui界面:

 

2.客户端代码

second.h

#ifndef SECOND_H
#define SECOND_H

#include <QWidget>
#include<QIcon>
#include<QTcpServer>//服务器头文件
#include<QTcpSocket>//客户端头文件
#include<QMessageBox>//消息对话框
#include<QDebug>//调试类


namespace Ui {
class Second;
}

class Second : public QWidget
{
    Q_OBJECT
public slots:
    void jump_slot();//接收跳转信号函数

public:
    explicit Second(QWidget *parent = nullptr);
    ~Second();

private slots:
    void on_connectBtn_clicked();//链接服务器对应的槽函数声明
    void connected_solt();
    void readyRead_slot();
    void dis_slot();

    void on_sendBtn_clicked();

    void on_disBtn_clicked();

private:
    Ui::Second *ui;
    //实例化一个客户端对象
    QTcpSocket *socket;

    //定义一个用户名的变量
    QString userName;
};

#endif // SECOND_H

 

widget.h 

 

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include<QMovie>//动态图
#include<QPixmap>//图片
#include<QDebug>//输出
#include<QPushButton>//按钮类
#include<QMessageBox>//信息类
#include<QIcon>//图片


QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
signals://自定义跳转信号函数
    void jump();

private slots:
    //void on_pushButton_2_clicked();
    void my_slot();//自己定义的槽函数


private:
    Ui::Widget *ui;


};
#endif // WIDGET_H

 

main.cpp

#include "widget.h"
#include"second.h"
#include <QApplication>

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

    //实例化第二个窗口的对象
    Second s;
    QObject::connect(&w,&Widget::jump,&s,&Second::jump_slot);
    return a.exec();
}

 

second.cpp

#include "second.h"
#include "ui_second.h"

void Second::jump_slot()//跳转信号槽函数
{
    this->show();//将自己的界面进行展示
}

Second::Second(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Second)
{
    ui->setupUi(this);

    //第二个界面的窗口设置
    this->setWindowTitle("划水摆烂群");
    this->setWindowIcon(QIcon(":/pictrue/eaeb1d87_E780070_63de2b7c.png"));

    //ui->listWidget->setStyleSheet("QListWidget { background-color: transparent; }");//设置背景为透明色


    //给客户端实例化空间
    socket =new QTcpSocket(this);

    //初始化界面(未连接服务器时)
    ui->msgEdit->setEnabled(false);//消息对话框不可用
    ui->sendBtn->setEnabled(false);//发送按钮不可用
    ui->disBtn->setEnabled(false);//离线不可用



    //判断是否连接成功,如果连接成功客户端会自动发射connected,将该信号连接到自定义的槽函数中处理相关的逻辑
    //因为只需要连接一次,所以我们将连接函数写在构造函数中
    connect(socket,&QTcpSocket::connected,this,&Second::connected_solt);//定义在构造函数是为了只连接一次

    //此时说明服务器和客户端此时已经建立好连接,如果服务器发来数据,该客户端会自动发射readRead信号
    connect(socket,&QTcpSocket::readyRead,this,&Second::readyRead_slot);


}


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

void Second::on_connectBtn_clicked()//链接服务器对应的槽函数
{
    //获取ui界面上的IP和端口号
    userName=ui->usernameEdit->text();//获取用户名
    QString ip=ui->ipEdit->text();//获取ip
    quint16 port=ui->portEdit_2->text().toUInt();//获取端口号
    //客户端连接服务器
    socket->connectToHost(ip,port);


}

void Second::connected_solt()//连接成功对应的槽函数
{
    //告诉服务器我上线了
    QString msg = userName + ":已上线";
    //将消息发送给服务器
    socket ->write(msg.toLocal8Bit());

    //重新设置ui界面上的控件
    ui->usernameEdit->setEnabled(false);
    ui->ipEdit->setEnabled(false);
    ui->portEdit_2->setEnabled(false);
    ui->connectBtn->setEnabled(false);



    ui->msgEdit->setEnabled(true);
    ui->sendBtn->setEnabled(true);
    ui->disBtn->setEnabled(true);



}

void Second::readyRead_slot()
{
    //说明服务器给客户端发来数据
    QByteArray msg = socket->readAll();
    //将数据放入到ui界面中
    ui->listWidget->addItem(QString::fromLocal8Bit(msg));
}

void Second::dis_slot()
{
    ui->usernameEdit->setEnabled(true);
    ui->ipEdit->setEnabled(true);
    ui->portEdit_2->setEnabled(true);
    ui->connectBtn->setEnabled(true);



    ui->msgEdit->setEnabled(false);
    ui->sendBtn->setEnabled(false);
    ui->disBtn->setEnabled(false);

}
void Second::on_sendBtn_clicked()//发送按钮对应的槽函数
{
    //获取ui界面上的文本内容
    QString msg =userName+":"+ ui->msgEdit->text();
    //将信息发送给服务器
    socket->write(msg.toLocal8Bit());

    //将msg的文本清空
    ui->msgEdit->clear();

}

void Second::on_disBtn_clicked()//离线按钮对应的槽函数
{
    QString msg = userName+":"+ "离开了聊天室,尔等也退下吧";
    socket->write(msg.toLocal8Bit());

    socket->disconnectFromHost();
}

 widget.cpp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //窗口图标设计
    this->setWindowTitle("腾讯QQ");
    this->setWindowIcon(QIcon(":/pictrue/20573cf63610bed.jpg"));

    //连接登录Btn信号与槽
    connect(ui->pushButton_2,&QPushButton::clicked,this,&Widget::my_slot);

    ui->zhuceBtn->setStyleSheet("border:1px solid transparent;");
    ui->mimaBtn->setStyleSheet("border:1px solid transparent;");//取消边框

/**********************标签设置****************************/
    //设置标签背景(动态图)
//    QMovie *mv = new QMovie("/*************路径*************/");
//    ui->beijinglabel->setMovie(mv);
//    mv->start();
    //让标签自动使用标签
    ui->beijinglabel->setPixmap(QPixmap(":/pictrue/wKjg2lvGWoCAJlJxAADOBePmF24715.jpg"));
    ui->beijinglabel->setScaledContents(true);

    //设置左上角的标签
//    ui->qqlable->setPixmap(QPixmap(":/pictrue/20573cf63610bed.jpg"));
//    ui->qqlable->setScaledContents(true);
//    ui->qqlable->resize(30,30);//重新设置大小

/**********************登录设置*******************************/






}

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


void Widget::my_slot()//登录按钮对应的槽函数
{
    QString userName =  ui->zhanghaoEdit->text();//获取账号
    QString passWord =  ui->mimaEdit->text();//获取密码


    //判断登录条件是否满足
    if(userName=="admin"&&passWord=="123456")
    {
        //满足登录条件跳转到聊天室页面
//        qDebug() << "deng";
//        this->close();
         emit jump();

        this->hide();//将自己的页面隐藏


    }else
    {
       // qDebug() << "";
        QMessageBox::information(this,"提示:","账号或密码错误请重新输入");
        //ui->zhanghaoEdit->clear();

    }

}

second的ui界面 

widget的ui界面 

 

实现效果: 

运行出的窗口

 

 密码输入错误弹出的消息对话框和启动服务器成功界面

输入信息上线成功显示界面 

 消息发送成功界面

离线显示下线信息

 


http://lihuaxi.xjx100.cn/news/1703953.html

相关文章

渲染过程JS 文件的处理方式

渲染过程中遇到 JS 文件怎么处理&#xff1f;&#xff08;浏览器解析过程&#xff09; JavaScript 的加载、解析与执行会阻塞文档的解析&#xff0c;也就是说&#xff0c;在构建 DOM 时&#xff0c;HTML 解析器若遇到了 JavaScript&#xff0c;那么它会暂停文档的解析&#xf…

商业智能的利用:打造成功的业务战略之道

在当今快节奏和数据驱动的商业环境中&#xff0c;制定稳健的商业战略对于实现可持续的增长和保持竞争力至关重要。商业智能&#xff08;BI&#xff09;是能够显著提高业务战略有效性的关键因素之一。本文将深入探讨商业智能的定义、其在战略制定中的重要性&#xff0c;以及如何…

PHP写用户注册、登录和密码重置功能

目录 连接数据库&#xff1a; 用户注册功能&#xff1a; 用户登录功能&#xff1a; 密码重置功能: 首先&#xff0c;创建一个名为users的数据库表&#xff0c;包含以下字段&#xff1a; id&#xff1a;用户ID&#xff0c;自增主键username&#xff1a;用户名&#xff0c;唯一…

Alluxio AI 全新产品发布:无缝对接低成本对象存储 AI 训练解决方案

&#xff08;2023 年 10 月 19 日&#xff0c;北京&#xff09;Alluxio 作为一家承载各类数据驱动型工作负载的数据平台公司&#xff0c;现推出全新的 Alluxio Enterprise AI 高性能数据平台, 旨在满足人工智能 (AI) 和机器学习 (ML) 负载对于企业数据基础设施不断增长的需求。…

实际项目中最常用的设计模式

在软件开发领域,设计模式是一种经过验证的通用解决方案,用于解决各种常见问题。它们有助于提高代码的可维护性、可扩展性和可重用性。虽然有许多不同的设计模式,但以下是实际项目中最常用的一些: 1. 单例模式 (Singleton Pattern) 单例模式确保一个类只有一个实例,并提供…

curl命令服务器上执行http请求

1. 现在本地使用postman生成curl命令 注意: 将ip改成127.0.0.1,端口是实际服务运行的端口 curl --location --request POST http://127.0.0.1:63040/content/course/list?pageNo1&pageSize2 \ --header Content-Type: application/json \ --data-raw {"courseName&q…

Http 缓存策略,有什么区别,分别解决了什么问题

1&#xff09;浏览器缓存策略 浏览器每次发起请求时&#xff0c;先在本地缓存中查找结果以及缓存标识&#xff0c;根据缓存标识来判断是否使用本地缓存。如果缓存有效&#xff0c;则使 用本地缓存&#xff1b;否则&#xff0c;则向服务器发起请求并携带缓存标识。根据是否需向服…

C#接口和继承的区别、联系与使用场景

在C#编程语言中&#xff0c;接口和继承是两个核心的概念。本文将详细介绍接口和继承之间的区别与联系&#xff0c;并探讨它们在实际编程中的使用场景。通过代码示例和详细说明&#xff0c;读者将能够深入理解这两个概念的功能和用法。 目录 引言1. 区别与联系1.1 区别1.2 联系 …