• QTday05(TCP的服务端客户端通信)


    实现聊天室功能

    服务端代码:

    pro文件需要导入  network

    头文件:

    1. #ifndef WIDGET_H
    2. #define WIDGET_H
    3. #include
    4. #include //服务端
    5. #include //客户端
    6. #include
    7. #include
    8. #include
    9. QT_BEGIN_NAMESPACE
    10. namespace Ui { class Widget; }
    11. QT_END_NAMESPACE
    12. class Widget : public QWidget
    13. {
    14. Q_OBJECT
    15. public:
    16. Widget(QWidget *parent = nullptr);
    17. ~Widget();
    18. private slots:
    19. void on_startBtn_clicked();
    20. public slots:
    21. void newConnectSlot();//建立连接的槽函数
    22. void readyReadSlot();//接收消息的槽函数
    23. private:
    24. Ui::Widget *ui;
    25. //实例化服务器对象
    26. QTcpServer *server;
    27. //创建存放客户端信息的容器
    28. QList socketList;
    29. };
    30. #endif // WIDGET_H

    widget.cpp

    1. #include "widget.h"
    2. #include "ui_widget.h"
    3. Widget::Widget(QWidget *parent)
    4. : QWidget(parent)
    5. , ui(new Ui::Widget)
    6. {
    7. ui->setupUi(this);
    8. //实例化服务器对象
    9. server=new QTcpServer(this);
    10. }
    11. Widget::~Widget()
    12. {
    13. delete ui;
    14. }
    15. void Widget::on_startBtn_clicked()
    16. {
    17. //监听任意ip的指定端口
    18. bool listen_res=server->listen(QHostAddress::Any,ui->portLine->text().toUInt());
    19. if(listen_res){
    20. //监听成功
    21. QMessageBox::information(this,"提示","设置监听成功",QMessageBox::Ok);
    22. }else{
    23. //监听失败
    24. QMessageBox::information(this,"提示","设置监听失败",QMessageBox::Ok);
    25. return;
    26. }
    27. //等待连接
    28. connect(server,&QTcpServer::newConnection,this,&Widget::newConnectSlot);
    29. }
    30. void Widget::newConnectSlot()
    31. {
    32. //接收到newConnect信号之后的槽函数,处理接下来的操作
    33. //获取客户端的套接字,加入容器
    34. QTcpSocket *s=server->nextPendingConnection();
    35. socketList.push_back(s);
    36. qDebug() << "有新客户连接" << s->peerName() << ";" << s->peerAddress().toString() << ":" << QString::number(s->peerPort()) <
    37. //此时如果客户端向服务器发送数据,客户端会发送一个readyRead信号
    38. connect(s,&QTcpSocket::readyRead,this,&Widget::readyReadSlot);
    39. }
    40. void Widget::readyReadSlot()
    41. {
    42. //客户端有数据发送,触发改槽函数
    43. //遍历容器,移除无效客户端,接收有效客户端消息
    44. for (int i=0;icount();i++) {
    45. //如果是非链接状态就移除
    46. if(socketList.at(i)->state()==QAbstractSocket::UnconnectedState){
    47. socketList.removeAt(i);
    48. }
    49. }
    50. for (int i=0;icount();i++) {
    51. //如果有字节,就读取并放到ui界面
    52. if(socketList.at(i)->bytesAvailable()){
    53. QByteArray msg=socketList.at(i)->readAll();
    54. QString msgInfo=socketList.at(i)->peerAddress().toString()+":"+QString::number(socketList.at(i)->peerPort())+":"+QString::fromLocal8Bit(msg);
    55. ui->listWidget->addItem(msgInfo);
    56. for (int j=0;jcount();j++) {
    57. socketList.at(j)->write(msg);
    58. }
    59. }
    60. }
    61. }

    ui:

    客户端代码:

    头文件

    1. #ifndef WIDGET_H
    2. #define WIDGET_H
    3. #include
    4. #include
    5. #include
    6. #include
    7. QT_BEGIN_NAMESPACE
    8. namespace Ui { class Widget; }
    9. QT_END_NAMESPACE
    10. class Widget : public QWidget
    11. {
    12. Q_OBJECT
    13. public:
    14. Widget(QWidget *parent = nullptr);
    15. ~Widget();
    16. private slots:
    17. void on_connnectBtn_clicked();
    18. void on_disconnectBtn_clicked();
    19. void on_sendBtn_clicked();
    20. public slots:
    21. void connnectedSlot();
    22. void readyReadSlot();
    23. void disconnectedSlot();
    24. private:
    25. Ui::Widget *ui;
    26. //实例化客户端
    27. QTcpSocket *socket;
    28. //定义全局变量存储用户名
    29. QString username;
    30. };
    31. #endif // WIDGET_H

    widget.cpp

    1. #include "widget.h"
    2. #include "ui_widget.h"
    3. Widget::Widget(QWidget *parent)
    4. : QWidget(parent)
    5. , ui(new Ui::Widget)
    6. {
    7. ui->setupUi(this);
    8. //实例化客户端
    9. socket=new QTcpSocket(this);
    10. //将发送和断开连接 的按钮默认设置不可用
    11. ui->sendBtn->setDisabled(true);
    12. ui->disconnectBtn->setDisabled(true);
    13. ui->accoutLine->setText("张三");
    14. ui->ipLine->setText("192.168.125.77");
    15. ui->portLine->setText("8888");
    16. //连接成功会触发connected信号,只需要一次
    17. connect(socket,&QTcpSocket::connected,this,&Widget::connnectedSlot);
    18. //收信号
    19. connect(socket,&QTcpSocket::readyRead,this,&Widget::readyReadSlot);
    20. connect(socket,&QTcpSocket::disconnected,this,&Widget::disconnectedSlot);
    21. }
    22. Widget::~Widget()
    23. {
    24. delete ui;
    25. }
    26. void Widget::on_connnectBtn_clicked()
    27. {
    28. //连接服务器
    29. username=ui->accoutLine->text();
    30. QString ip=ui->ipLine->text();
    31. quint16 port=ui->portLine->text().toUInt();
    32. socket->connectToHost(ip,port);
    33. //判断是否连接成功:连接成功后,户端会自动发射一个connected信号,
    34. }
    35. void Widget::connnectedSlot()
    36. {
    37. QMessageBox::information(this,"提示","连接成功");
    38. QString msg=username+"进入聊天室";
    39. socket->write(msg.toLocal8Bit());
    40. ui->sendBtn->setDisabled(false);
    41. ui->connnectBtn->setDisabled(true);
    42. ui->disconnectBtn->setDisabled(false);
    43. }
    44. void Widget::on_disconnectBtn_clicked()
    45. {
    46. QString msg=username+"离开聊天室";
    47. socket->write(msg.toLocal8Bit());
    48. socket->disconnectFromHost();
    49. }
    50. void Widget::on_sendBtn_clicked()
    51. {
    52. if(ui->infoLine->text().isEmpty()){
    53. QMessageBox::information(this,"提示","发送的消息不能为空");
    54. return;
    55. }
    56. QString msg=ui->infoLine->text();
    57. socket->write(msg.toLocal8Bit());
    58. ui->infoLine->setText("");
    59. }
    60. void Widget::readyReadSlot(){
    61. QByteArray msg=socket->readAll();
    62. ui->listWidget->addItem(QString::fromLocal8Bit(msg));
    63. }
    64. void Widget::disconnectedSlot()
    65. {
    66. ui->sendBtn->setDisabled(true);
    67. ui->disconnectBtn->setDisabled(true);
    68. ui->connnectBtn->setDisabled(false);
    69. QMessageBox::information(this,"提示","断开连接成功");
    70. }

    ui:

    运行结果:客户端连接之后可以成功发送信息

    今日思维导图

    将聊天功能加入到仿qq登录之后:

    代码:

    page2.h:

    1. #ifndef PAGE2_H
    2. #define PAGE2_H
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #define PORT 8888
    9. #define IP "192.168.125.77"
    10. namespace Ui {
    11. class Page2;
    12. }
    13. class Page2 : public QWidget
    14. {
    15. Q_OBJECT
    16. public:
    17. explicit Page2(QWidget *parent = nullptr);
    18. ~Page2();
    19. public slots:
    20. void login_slot();
    21. void connectedSlot();
    22. void readyReadSlot();
    23. private slots:
    24. void on_sendBtn_clicked();
    25. private:
    26. Ui::Page2 *ui;
    27. QTcpSocket *socket;
    28. };
    29. #endif // PAGE2_H

    widget.h:

    1. #ifndef WIDGET_H
    2. #define WIDGET_H
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. QT_BEGIN_NAMESPACE
    9. namespace Ui { class Widget; }
    10. QT_END_NAMESPACE
    11. class Widget : public QWidget
    12. {
    13. Q_OBJECT
    14. public:
    15. Widget(QWidget *parent = nullptr);
    16. ~Widget();
    17. void mousePressEvent(QMouseEvent *event) override;
    18. void mouseMoveEvent(QMouseEvent *event) override;
    19. public slots:
    20. void loginButton_slot();
    21. signals:
    22. void login_signal();
    23. private:
    24. Ui::Widget *ui;
    25. QPoint p;//定义全局变量p,记录位置
    26. public:
    27. static QString username;
    28. };
    29. #endif // WIDGET_H

    main.cpp:

    1. #include "widget.h"
    2. #include "page2.h"
    3. #include
    4. int main(int argc, char *argv[])
    5. {
    6. QApplication a(argc, argv);
    7. Widget w;
    8. w.show();
    9. Page2 p2;
    10. QObject::connect(&w,&Widget::login_signal,&p2,&Page2::login_slot);
    11. return a.exec();
    12. }

    page2.cpp:

    1. #include "page2.h"
    2. #include "widget.h"
    3. #include "ui_page2.h"
    4. Page2::Page2(QWidget *parent) :
    5. QWidget(parent),
    6. ui(new Ui::Page2)
    7. {
    8. ui->setupUi(this);
    9. QMovie *movie = new QMovie(":/111/cai.gif");
    10. ui->label->setMovie(movie);
    11. ui->label->setScaledContents(true);
    12. movie->start();
    13. //实例化客户端
    14. socket=new QTcpSocket(this);
    15. qDebug() << "实例化客户端";
    16. //建立connected信号和指定槽函数的连接
    17. connect(socket,&QTcpSocket::connected,this,&Page2::connectedSlot);
    18. //建立readyRead信号和指定槽函数连接
    19. connect(socket,&QTcpSocket::readyRead,this,&Page2::readyReadSlot);
    20. }
    21. Page2::~Page2()
    22. {
    23. delete ui;
    24. }
    25. void Page2::login_slot()
    26. {
    27. qDebug() << "登录按钮";
    28. this->show();
    29. //连接客户端
    30. socket->connectToHost(IP,PORT);
    31. }
    32. void Page2::connectedSlot()
    33. {
    34. //连接成功后触发该槽函数
    35. qDebug() << "连接成功";
    36. QMessageBox::information(this,"提示","连接成功");
    37. QString msg=Widget::username+"加入了聊天";
    38. socket->write(msg.toLocal8Bit());
    39. }
    40. void Page2::readyReadSlot()
    41. {
    42. //收到服务端发送的消息时触发该槽函数
    43. QByteArray msg=socket->readAll();
    44. ui->listWidget->addItem(QString::fromLocal8Bit(msg));
    45. }
    46. void Page2::on_sendBtn_clicked()
    47. {
    48. if(ui->infoEdit->toPlainText().isEmpty()){
    49. QMessageBox::information(this,"提示","发送的消息不能为空");
    50. return;
    51. }
    52. QString msg=ui->infoEdit->toPlainText();
    53. socket->write(msg.toLocal8Bit());
    54. ui->infoEdit->clear();
    55. }

    widget.cpp:

    1. #include "widget.h"
    2. #include "ui_widget.h"
    3. QString Widget::username="";
    4. Widget::Widget(QWidget *parent)
    5. : QWidget(parent)
    6. , ui(new Ui::Widget)
    7. {
    8. ui->setupUi(this);
    9. this->setFixedSize(560,430);
    10. this->setStyleSheet("background-color:#faf7ec");
    11. this->setWindowFlag(Qt::FramelessWindowHint);//无边框
    12. QMovie *movie = new QMovie(":/111/cai.gif");
    13. ui->backLabel->setMovie(movie);
    14. ui->backLabel->setScaledContents(true);
    15. movie->start();
    16. ui->closeButton->setStyleSheet("border-image:url(:/111/basketball.png)");
    17. ui->avatorLabel->resize(60,60);
    18. ui->avatorLabel->setStyleSheet("border-image:url(:/111/user.png);border-radius:30px");
    19. ui->accountLabel->setPixmap(QPixmap(":/111/account.jpg"));
    20. //ui->accountLabel->resize(40,40);
    21. ui->accountLabel->setScaledContents(true);
    22. ui->passwdLabel->setPixmap(QPixmap(":/111/passwd.jpg"));
    23. //ui->passwdLabel->resize(40,40);
    24. ui->passwdLabel->setScaledContents(true);
    25. ui->accoountLine->setPlaceholderText("账号");
    26. ui->passwdLine->setPlaceholderText("密码");
    27. ui->passwdLine->setEchoMode(QLineEdit::Password);
    28. ui->loginLabel->setPixmap(QPixmap(":/111/2.png"));
    29. ui->loginLabel->setScaledContents(true);
    30. ui->loginButton->setStyleSheet("background-color:#409EFF;border-radius:5px");
    31. connect(ui->closeButton,SIGNAL(clicked()),this,SLOT(close()));
    32. connect(ui->loginButton,&QPushButton::clicked,this,&Widget::loginButton_slot);
    33. }
    34. Widget::~Widget()
    35. {
    36. delete ui;
    37. }
    38. void Widget::loginButton_slot()
    39. {
    40. //判断用户账号密码的正确性
    41. if(ui->accoountLine->text()=="admin"&&ui->passwdLine->text()=="123456"){
    42. username="admin";
    43. qDebug() << "登录成功" <
    44. QMessageBox::information(this,"提示","登录成功",QMessageBox::Ok);
    45. this->close();
    46. //开启新窗口,手动触发信号
    47. emit login_signal();
    48. }else{
    49. qDebug() << "账号或者密码错误" <
    50. int res=QMessageBox::information(this,"提示","账号或者密码错误,是否继续登录",QMessageBox::Ok|QMessageBox::No);
    51. if(res==QMessageBox::Ok){
    52. ui->passwdLine->setText("");
    53. }else{
    54. this->close();
    55. }
    56. }
    57. }
    58. void Widget::mousePressEvent(QMouseEvent *event){
    59. p=event->pos();
    60. }
    61. void Widget::mouseMoveEvent(QMouseEvent *event){
    62. if(event->buttons()==Qt::LeftButton)
    63. this->move(event->globalPos()-p);
    64. }

    page2.ui:

    widget.ui:

    运行结果:

  • 相关阅读:
    第18章_瑞萨MCU零基础入门系列教程之GPT
    去面试了几家BATJ等N家互联网大厂
    【LeetCode】【剑指offer】【队列的最大值(二)】
    熟悉又陌生的package.json
    【嵌入式开发 Linux 常用命令系列 7.2 -- awk 找到空格并插入字符】
    Activiti进阶
    【gcc/g++】2.三大编译方式(直接编译库 静态链接库 动态链接库)
    2024年(上海) 集成软件及系统管理博览会
    uniapp 底部导航 点击刷新当前页
    基本算法模板整理——链表,二叉树,快速排序
  • 原文地址:https://blog.csdn.net/weixin_53762703/article/details/133965142