• 【无标题】


    客户端每隔10ms向服务器发送一次数字字符串,从0开始。

    1. #ifndef MAINWINDOW_H
    2. #define MAINWINDOW_H
    3. #include
    4. #include
    5. #include
    6. #include
    7. namespace Ui {
    8. class MainWindow;
    9. }
    10. class MainWindow : public QMainWindow
    11. {
    12. Q_OBJECT
    13. private:
    14. QTcpSocket *tcpClient; //socket
    15. QLabel *LabSocketState; //状态栏显示标签
    16. QString getLocalIP();//获取本机IP地址
    17. protected:
    18. void closeEvent(QCloseEvent *event);
    19. public:
    20. explicit MainWindow(QWidget *parent = 0);
    21. ~MainWindow();
    22. private slots:
    23. //自定义槽函数
    24. void onConnected();
    25. void onDisconnected();
    26. void onSocketStateChange(QAbstractSocket::SocketState socketState);
    27. void onSocketReadyRead();//读取socket传入的数据
    28. //
    29. void on_actConnect_triggered();
    30. void on_actDisconnect_triggered();
    31. void on_actClear_triggered();
    32. void on_pushButton_clicked();
    33. void send_msg();
    34. private:
    35. Ui::MainWindow *ui;
    36. QTimer* timer;
    37. };
    38. #endif // MAINWINDOW_H

    关键:

    QTimer* timer;

    1. #include "mainwindow.h"
    2. #include "ui_mainwindow.h"
    3. #include
    4. #include
    5. #include
    6. QString MainWindow::getLocalIP()
    7. {
    8. QString hostName=QHostInfo::localHostName();//本地主机名
    9. QHostInfo hostInfo=QHostInfo::fromName(hostName);
    10. QString localIP="";
    11. QList addList=hostInfo.addresses();//
    12. if (!addList.isEmpty())
    13. for (int i=0;icount();i++)
    14. {
    15. QHostAddress aHost=addList.at(i);
    16. if (QAbstractSocket::IPv4Protocol==aHost.protocol())
    17. {
    18. localIP=aHost.toString();
    19. break;
    20. }
    21. }
    22. return localIP;
    23. }
    24. void MainWindow::closeEvent(QCloseEvent *event)
    25. {
    26. if (tcpClient->state()==QAbstractSocket::ConnectedState)
    27. tcpClient->disconnectFromHost();
    28. event->accept();
    29. }
    30. MainWindow::MainWindow(QWidget *parent) :
    31. QMainWindow(parent),
    32. ui(new Ui::MainWindow)
    33. {
    34. ui->setupUi(this);
    35. tcpClient=new QTcpSocket(this); //创建socket变量
    36. timer = new QTimer(this);
    37. connect(timer, SIGNAL(timeout()), this, SLOT(send_msg()));
    38. LabSocketState=new QLabel("Socket状态:");//状态栏标签
    39. LabSocketState->setMinimumWidth(250);
    40. ui->statusBar->addWidget(LabSocketState);
    41. QString localIP=getLocalIP();//本机IP
    42. this->setWindowTitle(this->windowTitle()+"----本机IP:"+localIP);
    43. ui->comboServer->addItem(localIP);
    44. connect(tcpClient,SIGNAL(connected()),this,SLOT(onConnected()));
    45. connect(tcpClient,SIGNAL(disconnected()),this,SLOT(onDisconnected()));
    46. connect(tcpClient,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
    47. this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
    48. connect(tcpClient,SIGNAL(readyRead()),
    49. this,SLOT(onSocketReadyRead()));
    50. }
    51. MainWindow::~MainWindow()
    52. {
    53. delete ui;
    54. }
    55. void MainWindow::onConnected()
    56. { //connected()信号槽函数
    57. ui->plainTextEdit->appendPlainText("**已连接到服务器");
    58. ui->plainTextEdit->appendPlainText("**peer address:"+
    59. tcpClient->peerAddress().toString());
    60. ui->plainTextEdit->appendPlainText("**peer port:"+
    61. QString::number(tcpClient->peerPort()));
    62. ui->actConnect->setEnabled(false);
    63. ui->actDisconnect->setEnabled(true);
    64. }
    65. void MainWindow::onDisconnected()
    66. {//disConnected()信号槽函数
    67. ui->plainTextEdit->appendPlainText("**已断开与服务器的连接");
    68. ui->actConnect->setEnabled(true);
    69. ui->actDisconnect->setEnabled(false);
    70. }
    71. void MainWindow::onSocketReadyRead()
    72. {//readyRead()信号槽函数
    73. while(tcpClient->canReadLine())
    74. ui->plainTextEdit->appendPlainText("[in] "+tcpClient->readLine());
    75. }
    76. void MainWindow::onSocketStateChange(QAbstractSocket::SocketState socketState)
    77. {//stateChange()信号槽函数
    78. switch(socketState)
    79. {
    80. case QAbstractSocket::UnconnectedState:
    81. LabSocketState->setText("scoket状态:UnconnectedState");
    82. break;
    83. case QAbstractSocket::HostLookupState:
    84. LabSocketState->setText("scoket状态:HostLookupState");
    85. break;
    86. case QAbstractSocket::ConnectingState:
    87. LabSocketState->setText("scoket状态:ConnectingState");
    88. break;
    89. case QAbstractSocket::ConnectedState:
    90. LabSocketState->setText("scoket状态:ConnectedState");
    91. break;
    92. case QAbstractSocket::BoundState:
    93. LabSocketState->setText("scoket状态:BoundState");
    94. break;
    95. case QAbstractSocket::ClosingState:
    96. LabSocketState->setText("scoket状态:ClosingState");
    97. break;
    98. case QAbstractSocket::ListeningState:
    99. LabSocketState->setText("scoket状态:ListeningState");
    100. }
    101. }
    102. void MainWindow::on_actConnect_triggered()
    103. {//连接到服务器
    104. QString addr=ui->comboServer->currentText();
    105. quint16 port=ui->spinPort->value();
    106. tcpClient->connectToHost(addr,port);
    107. // tcpClient->connectToHost(QHostAddress::LocalHost,port);
    108. }
    109. void MainWindow::on_actDisconnect_triggered()
    110. {//断开与服务器的连接
    111. if (tcpClient->state()==QAbstractSocket::ConnectedState)
    112. tcpClient->disconnectFromHost();
    113. }
    114. void MainWindow::on_actClear_triggered()
    115. {
    116. ui->plainTextEdit->clear();
    117. }
    118. void MainWindow::on_pushButton_clicked()
    119. {
    120. timer->start(10);
    121. }
    122. void MainWindow::send_msg()
    123. {
    124. static int m = 0;
    125. QString msg = QString::number(m);
    126. ui->plainTextEdit->appendPlainText("[out] " + msg);
    127. QByteArray str = msg.toUtf8();
    128. str.append('\n');
    129. tcpClient->write(str);
    130. m++;
    131. }

    关键:

    1. timer = new QTimer(this);
    2. connect(timer, SIGNAL(timeout()), this, SLOT(send_msg()));
    1. void MainWindow::on_pushButton_clicked()
    2. {
    3. timer->start(10);
    4. }
    5. void MainWindow::send_msg()
    6. {
    7. static int m = 0;
    8. QString msg = QString::number(m);
    9. ui->plainTextEdit->appendPlainText("[out] " + msg);
    10. QByteArray str = msg.toUtf8();
    11. str.append('\n');
    12. tcpClient->write(str);
    13. m++;
    14. }

    修改:

    1. void MainWindow::on_pushButton_clicked()
    2. {
    3. timer->start(1);
    4. }

    客户端每1ms向服务器发送一个数字,此时也可以。

    如果客户端中:

    1. while (1)
    2. {
    3. QString msg = QString::number(1);
    4. //ui->plainTextEdit->appendPlainText("[out] " + msg);
    5. qDebug() << "[out] " + msg;
    6. QByteArray str = msg.toUtf8();
    7. str.append('\n');
    8. tcpClient->write(str);
    9. }

    不断向服务器发送信息,此时页面是卡到一点都动不了,所以需要使用多线程来处理。

     一种错误的写法:

    1. #include "workThread.h"
    2. #include
    3. #include
    4. #include
    5. workThread::workThread(QTcpSocket* tcpClient,QObject *parent)
    6. : QThread(parent)
    7. {
    8. qDebug()<<"workThread::workThread" << QThread::currentThread();
    9. this->tcpClient = tcpClient;
    10. timer = new QTimer(this);
    11. connect(timer, &QTimer::timeout, this, [=]() {
    12. ok = false;
    13. });
    14. timer->start(1000);
    15. }
    16. workThread::~workThread()
    17. {
    18. }
    19. void workThread::run()
    20. {
    21. qDebug() <<"run():" << QThread::currentThread();
    22. send_msg();
    23. }
    24. void workThread::send_msg()
    25. {
    26. qDebug() <<"send_msg():" << QThread::currentThread();
    27. while (1)
    28. {
    29. QString msg = QString::number(1);
    30. if (ok == false) {
    31. qDebug() << "[out] " + msg;
    32. ok = true;
    33. }
    34. QByteArray str = msg.toUtf8();
    35. str.append('\n');
    36. tcpClient->write(str);
    37. }
    38. }

    workThread::workThread QThread(0xbde160)
    run(): workThread(0xc744b0)
    send_msg(): workThread(0xc744b0)
    QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread

    QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread报错-CSDN博客

    1. class workThread : public QThread
    2. {
    3. Q_OBJECT
    4. signals:
    5. public:
    6. workThread(QObject *parent);
    7. ~workThread();
    8. protected:
    9. void run();
    10. private:
    11. QTcpSocket* tcpClient; //socket
    12. };
    1. void workThread::run()
    2. {
    3. qDebug() <<"run():" << QThread::currentThread();
    4. tcpClient = new QTcpSocket(this); //创建socket变量
    5. }

    这样写会导致:

     QObject: Cannot create children for a parent that is in a different thread.
    (Parent is workThread(0xc194f0), parent's thread is QThread(0xb7f940), current thread is workThread(0xc194f0)

     关键在这句:

    tcpClient = new QTcpSocket(this); //创建socket变量

    this是主线程(0xb7f940)的,而当前线程是子线程(0xc194f0)。

    tcpClient是子线程的(0xc194f0)。

    不允许出现,父亲(this)与孩子(tcpClient)是不同线程的对象,这样的情况。

    可以这样写:

    1. void workThread::run()
    2. {
    3. qDebug() <<"run():" << QThread::currentThread();
    4. tcpClient = new QTcpSocket; //创建socket变量
    5. }

    另一种错误写法:

    1. void workThread::run()
    2. {
    3. qDebug() <<"run():" << QThread::currentThread();
    4. tcpClient = new QTcpSocket; //创建socket变量
    5. MainWindow* window = (MainWindow*)(parent());
    6. connect(window, &MainWindow::connectToHost, this, &workThread::connectToHost, Qt::QueuedConnection);
    7. qDebug() << "......";
    8. }
    9. void workThread::connectToHost(QString addr, quint16 port)
    10. {
    11. qDebug() << "workThread::connectToHost:" << QThread::currentThread();
    12. tcpClient->connectToHost(addr, port);
    13. }

    run(): workThread(0x108f510)
    ......
    workThread::connectToHost: QThread(0x100fa30)
    QObject: Cannot create children for a parent that is in a different thread.
    (Parent is QTcpSocket(0x109c458), parent's thread is workThread(0x108f510), current thread is QThread(0x100fa30)

    run()函数:工作线程(0x108f510)

    connectToHost槽函数:主线程(0x100fa30)

    有一个QObject子类对象:假设它的对象名为m。

    它的parent()为QTcpSocket(0x109c458),QTcpSocket(0x109c458)所在的线程是工作线程(0x108f510),当前线程是主线程(0x100fa30)。

    然后出现了这样的错误。

    这种情况和上面的错误情况类似。

    关键:

    主线程中的对象m

    子线程的对象n

    m不可以是n的parent

    n不可以是m的parent

    另一种思路:

    再封装一个QObject子类:

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. class socket : public QObject
    6. {
    7. Q_OBJECT
    8. public:
    9. socket(QObject *parent=nullptr);
    10. ~socket();
    11. public slots:
    12. void connectToHost(QString hostName, quint16 port);
    13. void send_msg();
    14. private:
    15. QTcpSocket* tcpClient; //socket
    16. QTimer* timer;
    17. bool ok;
    18. };
    1. #include "socket.h"
    2. #include
    3. #include
    4. socket::socket(QObject *parent)
    5. : QObject(parent)
    6. {
    7. qDebug() << "socket::socket:" << QThread::currentThread();
    8. timer = new QTimer(this);
    9. tcpClient = new QTcpSocket(this); //创建socket变量
    10. connect(timer, &QTimer::timeout, this, [=]() {
    11. ok = false;
    12. });
    13. timer->start(10000);
    14. }
    15. socket::~socket()
    16. {
    17. }
    18. void socket::connectToHost(QString addr, quint16 port)
    19. {
    20. qDebug() << "socket::connectToHost:" << QThread::currentThread();
    21. tcpClient->connectToHost(addr, port);
    22. }
    23. void socket::send_msg()
    24. {
    25. qDebug() <<"socket::send_msg():" << QThread::currentThread();
    26. while (1)
    27. {
    28. QString msg = QString::number(1);
    29. if (ok == false) {
    30. qDebug() << "[out] " + msg;
    31. ok = true;
    32. }
    33. QByteArray str = msg.toUtf8();
    34. str.append('\n');
    35. tcpClient->write(str);
    36. }
    37. }
    1. void workThread::run()
    2. {
    3. qDebug() <<"run():" << QThread::currentThread();
    4. tcp_client = new socket;
    5. MainWindow* window = (MainWindow*)(parent());
    6. connect(window, &MainWindow::connectToHost, tcp_client, &socket::connectToHost);
    7. qDebug() << "......";
    8. }

    这样写的话,不会出现前面的问题。

    但出现了新问题,window发送了connectToHost,而tcp_client没有执行connectToHost。

    因为子线程没有开启事件循环。

    【QT】跨线程的信号槽(connect函数)_qt跨线程信号槽-CSDN博客

    QThread::exec();

    1. void workThread::run()
    2. {
    3. qDebug() <<"run():" << QThread::currentThread();
    4. tcp_client = new socket;
    5. MainWindow* window = (MainWindow*)(parent());
    6. connect(window, &MainWindow::connectToHost, tcp_client, &socket::connectToHost);
    7. qDebug() << "......";
    8. QThread::exec();
    9. }

    此时主线程就可以跨线程向子线程通过信号槽发送信息啦。

    思考:

    connect(window, &MainWindow::connectToHost, tcp_client, &socket::connectToHost);

    connectToHost槽函数在哪个线程执行,取决于tcp_client对象在哪个线程。

    客户端:

    多线程版本

    在子线程中:每1ms向服务器发送一次数据。

    (还有很多bug)

    (绑定的资源文件对应这个版本)

  • 相关阅读:
    8.7 迁移学习域适应
    面试必问 创建10个a点击弹出下标
    使用 Redis BitMap 实现签到与查询历史签到以及签到统计功能(SpringBoot环境)
    Linux系统下查看版本信息
    【Yocto2】构建嵌入式Linux系统
    javaweb没有web.xml设置方法
    Flink SQL通过Hudi HMS Catalog读写Hudi并同步Hive表(强烈推荐这种方式)
    Docker 使用 IDEA 内置插件构建上传镜像 与 SSH、FTP 功能使用
    java计算机毕业设计三门峡市旅游景点一站式服务规划系统演示录像源码+数据库+系统+lw文档+mybatis+运行部署
    Codeforces Round #821(Div.2) (A-D2) 题解
  • 原文地址:https://blog.csdn.net/weixin_51883798/article/details/138156671