使用QTcpSocket

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

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include  <QTcpSocket>
#include  <QLabel>
#include <QTimer>
namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT
private:
    QTcpSocket  *tcpClient;  //socket
    QLabel  *LabSocketState;  //状态栏显示标签

    QString getLocalIP();//获取本机IP地址
protected:
    void    closeEvent(QCloseEvent *event);
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
//自定义槽函数
    void    onConnected();
    void    onDisconnected();
    void    onSocketStateChange(QAbstractSocket::SocketState socketState);
    void    onSocketReadyRead();//读取socket传入的数据
//
    void on_actConnect_triggered();

    void on_actDisconnect_triggered();

    void on_actClear_triggered();

    void on_pushButton_clicked();

    void send_msg();

private:
    Ui::MainWindow *ui;
    QTimer* timer;
};

#endif // MAINWINDOW_H

关键:

QTimer* timer;

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include    <QHostAddress>
#include    <QHostInfo>
#include    <QThread>
QString MainWindow::getLocalIP()
{
    QString hostName=QHostInfo::localHostName();//本地主机名
    QHostInfo   hostInfo=QHostInfo::fromName(hostName);
    QString   localIP="";

    QList<QHostAddress> addList=hostInfo.addresses();//

    if (!addList.isEmpty())
    for (int i=0;i<addList.count();i++)
    {
        QHostAddress aHost=addList.at(i);
        if (QAbstractSocket::IPv4Protocol==aHost.protocol())
        {
            localIP=aHost.toString();
            break;
        }
    }
    return localIP;
}
void MainWindow::closeEvent(QCloseEvent *event)
{
    if (tcpClient->state()==QAbstractSocket::ConnectedState)
        tcpClient->disconnectFromHost();
    event->accept();
}

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

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

    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(send_msg()));

    LabSocketState=new QLabel("Socket状态:");//状态栏标签
    LabSocketState->setMinimumWidth(250);
    ui->statusBar->addWidget(LabSocketState);

    QString localIP=getLocalIP();//本机IP
    this->setWindowTitle(this->windowTitle()+"----本机IP:"+localIP);
    ui->comboServer->addItem(localIP);


    connect(tcpClient,SIGNAL(connected()),this,SLOT(onConnected()));
    connect(tcpClient,SIGNAL(disconnected()),this,SLOT(onDisconnected()));

    connect(tcpClient,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
    connect(tcpClient,SIGNAL(readyRead()),
            this,SLOT(onSocketReadyRead()));
}

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

void MainWindow::onConnected()
{ //connected()信号槽函数
    ui->plainTextEdit->appendPlainText("**已连接到服务器");
    ui->plainTextEdit->appendPlainText("**peer address:"+
                                   tcpClient->peerAddress().toString());
    ui->plainTextEdit->appendPlainText("**peer port:"+
                                   QString::number(tcpClient->peerPort()));
    ui->actConnect->setEnabled(false);
    ui->actDisconnect->setEnabled(true);
}

void MainWindow::onDisconnected()
{//disConnected()信号槽函数
    ui->plainTextEdit->appendPlainText("**已断开与服务器的连接");
    ui->actConnect->setEnabled(true);
    ui->actDisconnect->setEnabled(false);
}

void MainWindow::onSocketReadyRead()
{//readyRead()信号槽函数
    while(tcpClient->canReadLine())
        ui->plainTextEdit->appendPlainText("[in] "+tcpClient->readLine());
}

void MainWindow::onSocketStateChange(QAbstractSocket::SocketState socketState)
{//stateChange()信号槽函数
    switch(socketState)
    {
    case QAbstractSocket::UnconnectedState:
        LabSocketState->setText("scoket状态:UnconnectedState");
        break;
    case QAbstractSocket::HostLookupState:
        LabSocketState->setText("scoket状态:HostLookupState");
        break;
    case QAbstractSocket::ConnectingState:
        LabSocketState->setText("scoket状态:ConnectingState");
        break;

    case QAbstractSocket::ConnectedState:
        LabSocketState->setText("scoket状态:ConnectedState");
        break;

    case QAbstractSocket::BoundState:
        LabSocketState->setText("scoket状态:BoundState");
        break;

    case QAbstractSocket::ClosingState:
        LabSocketState->setText("scoket状态:ClosingState");
        break;

    case QAbstractSocket::ListeningState:
        LabSocketState->setText("scoket状态:ListeningState");
    }
}

void MainWindow::on_actConnect_triggered()
{//连接到服务器
    QString     addr=ui->comboServer->currentText();
    quint16     port=ui->spinPort->value();
    tcpClient->connectToHost(addr,port);
//    tcpClient->connectToHost(QHostAddress::LocalHost,port);

    
}

void MainWindow::on_actDisconnect_triggered()
{//断开与服务器的连接
    if (tcpClient->state()==QAbstractSocket::ConnectedState)
        tcpClient->disconnectFromHost();
}

void MainWindow::on_actClear_triggered()
{
    ui->plainTextEdit->clear();
}

void MainWindow::on_pushButton_clicked()
{
    timer->start(10);
}
void MainWindow::send_msg()
{
    static int m = 0;
    QString msg = QString::number(m);

    ui->plainTextEdit->appendPlainText("[out] " + msg);

    QByteArray  str = msg.toUtf8();
    str.append('\n');
    tcpClient->write(str);

    m++;
}

关键:

    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(send_msg()));
void MainWindow::on_pushButton_clicked()
{
    timer->start(10);
}
void MainWindow::send_msg()
{
    static int m = 0;
    QString msg = QString::number(m);

    ui->plainTextEdit->appendPlainText("[out] " + msg);

    QByteArray  str = msg.toUtf8();
    str.append('\n');
    tcpClient->write(str);

    m++;
}

修改:

void MainWindow::on_pushButton_clicked()
{
    timer->start(1);
}

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

如果客户端中:

    while (1)
    {
        QString msg = QString::number(1);

        //ui->plainTextEdit->appendPlainText("[out] " + msg);
        qDebug() << "[out] " + msg;
        QByteArray  str = msg.toUtf8();
        str.append('\n');
        tcpClient->write(str);
    }

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

 一种错误的写法:

#include "workThread.h"
#include <qapplication.h>
#include <qfiledialog.h>
#include <qdebug.h>

workThread::workThread(QTcpSocket* tcpClient,QObject *parent)
	: QThread(parent)
{
   qDebug()<<"workThread::workThread" << QThread::currentThread();
   this->tcpClient = tcpClient;
   timer = new QTimer(this);
   connect(timer, &QTimer::timeout, this, [=]() {
       ok = false;
       });
   timer->start(1000);
}

workThread::~workThread()
{
}
void workThread::run()
{
    qDebug() <<"run():" << QThread::currentThread();
    send_msg();
}
void workThread::send_msg()
{
    qDebug() <<"send_msg():" << QThread::currentThread();
    while (1)
    {
        QString msg = QString::number(1);
        if (ok == false) {
            qDebug() << "[out] " + msg;
            ok = true;
        }
        QByteArray  str = msg.toUtf8();
        str.append('\n');
        tcpClient->write(str);
    }
}

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博客

class workThread  : public QThread
{
	Q_OBJECT
signals:

public:
	workThread(QObject *parent);
	~workThread();
protected:
	void run();
private:
	QTcpSocket* tcpClient;  //socket
};
void workThread::run()
{
    qDebug() <<"run():" << QThread::currentThread();
    tcpClient = new QTcpSocket(this); //创建socket变量

}

这样写会导致:

 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)是不同线程的对象,这样的情况。

可以这样写:

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

另一种错误写法:

void workThread::run()
{
    qDebug() <<"run():" << QThread::currentThread();
    tcpClient = new QTcpSocket; //创建socket变量
    MainWindow* window = (MainWindow*)(parent());
    connect(window, &MainWindow::connectToHost, this, &workThread::connectToHost, Qt::QueuedConnection);
    qDebug() << "......";
}
void workThread::connectToHost(QString addr, quint16 port)
{
    qDebug() << "workThread::connectToHost:" << QThread::currentThread();
    tcpClient->connectToHost(addr, port);
}

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子类:

#pragma once

#include <QObject>
#include <QTcpSocket>
#include <qtimer.h>
class socket  : public QObject
{
	Q_OBJECT

public:
	socket(QObject *parent=nullptr);
	~socket();
public slots:
	void connectToHost(QString hostName, quint16 port);
	void send_msg();
private:
	QTcpSocket* tcpClient;  //socket
	QTimer* timer;
	bool ok;
};
#include "socket.h"
#include <qdebug.h>
#include <QThread>
socket::socket(QObject *parent)
	: QObject(parent)
{
    qDebug() << "socket::socket:" << QThread::currentThread();
    timer = new QTimer(this);
    tcpClient = new QTcpSocket(this); //创建socket变量
    connect(timer, &QTimer::timeout, this, [=]() {
        ok = false;
        });
    timer->start(10000);
}

socket::~socket()
{
}
void socket::connectToHost(QString addr, quint16 port)
{
    qDebug() << "socket::connectToHost:" << QThread::currentThread();
    tcpClient->connectToHost(addr, port);
}
void socket::send_msg()
{
    qDebug() <<"socket::send_msg():" << QThread::currentThread();
    while (1)
    {
        QString msg = QString::number(1);
        if (ok == false) {
            qDebug() << "[out] " + msg;
            ok = true;
        }
        QByteArray  str = msg.toUtf8();
        str.append('\n');
        tcpClient->write(str);
    }
}
void workThread::run()
{
    qDebug() <<"run():" << QThread::currentThread();
    tcp_client = new socket;
    MainWindow* window = (MainWindow*)(parent());
    connect(window, &MainWindow::connectToHost, tcp_client, &socket::connectToHost);
    qDebug() << "......";

}

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

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

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

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

QThread::exec();

void workThread::run()
{
    qDebug() <<"run():" << QThread::currentThread();
    tcp_client = new socket;
    MainWindow* window = (MainWindow*)(parent());
    connect(window, &MainWindow::connectToHost, tcp_client, &socket::connectToHost);
    qDebug() << "......";

    QThread::exec();
}

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

思考:

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

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

客户端:

多线程版本

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

(还有很多bug)

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/580346.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MAVEN的安装与配置

MAVEN的安装与配置 1 简介 1.1 什么是MAVEN? Maven是一个项目构建及管理工具&#xff0c;开发团队几乎不用花多少时间就能够自动完成工程的基础构建配置&#xff0c; Maven 使用了一个标准的目录结构在不同开发工具中也能实现项目结构的统一。Maven提供了清理&#xff0c;编…

【Vue】组件化编程

定义 实现应用中局部功能代码和资源的集合 为什么要用组件化编程? 传统方式编写:依赖关系混乱,不好维护,且代码复用率不高 模块化编写:只关注解决js,复用js,简化js的编写与效率 组件方式编写:好维护、复用率更高、提高运行效率 在组件出现之前,我们开发基本都是用htm…

【综述】DSP处理器芯片

文章目录 TI DSP C2000系列 TMS320F28003X 典型应用 开发工具链 参考资料 TI DSP TI C2000系列 控制领域 TI C5000系列 通信领域 TI C6000系列 图像领域 C2000系列 第三代集成了C28浮点DSP内核&#xff0c;采用了65nm工艺&#xff08;上一代180nm&#xff09; 第四代正在…

PyCharm 无法运行的解决方案

问题&#xff1a; PyCharm 无法运行&#xff0c;该怎么办&#xff1f; 解决方案&#xff1a; 1. 检查 Python 解释器 确保已为 PyCharm 配置正确的 Python 解释器。打开 PyCharm&#xff0c;转到“文件”>“设置”>“项目”>“Python 解释器”。选择所需的 Python …

怎么在海外平台买东西?Nike海淘攻略

不管在那个海外平台买东西首先要进入官网&#xff0c;最好注册一个gmail账号&#xff0c;这样使用范围比较宽广&#xff0c;在对应平台进行注册账号&#xff0c;比如亚马逊、ebay、Etsy等等 一、Nike海淘攻略 1、然后如果已经会员的话直接输入账号密码登录&#xff0c;如果不…

AI大模型探索之路-训练篇3:大语言模型全景解读

文章目录 前言一、语言模型发展历程1. 第一阶段&#xff1a;统计语言模型&#xff08;Statistical Language Model, SLM&#xff09;2. 第二阶段&#xff1a;神经语言模型&#xff08;Neural Language Model, NLM&#xff09;3. 第三阶段&#xff1a;预训练语言模型&#xff08…

顺通拖鞋ERP企业销售管理系统:驱动销售业绩飙升的利器

顺通企业销售管理系统通过集成客户信息、销售流程、数据分析等功能&#xff0c;帮助企业全面提升销售效率和业绩&#xff0c;成为驱动销售业绩飙升的利器。此外&#xff0c;系统还支持销售流程的可视化展示&#xff0c;使销售人员能够清晰地了解销售进展&#xff0c;及时调整销…

短视频账号矩阵系统===4年技术源头打磨

短视频矩阵系统技术源头打磨需要从多个方面入手&#xff0c;以下是一些建议&#xff1a; 1. 基础技术研发&#xff1a;不断投入资金和人力进行基础技术研发&#xff0c;包括但不限于视频处理、人工智能、大数据等技术&#xff0c;以提高短视频矩阵系统的性能和稳定性。 2. 优化…

JAVA面试八股文之JVM

JVM JVM由那些部分组成&#xff0c;运行流程是什么&#xff1f;你能详细说一下 JVM 运行时数据区吗&#xff1f;详细介绍一下程序计数器的作用&#xff1f;你能给我详细的介绍Java堆吗?什么是虚拟机栈&#xff1f;栈内存溢出情况&#xff1f;堆栈的区别是什么吗&#xff1f;解…

深入理解分布式事务② ---->分布式事务基础(MySQL 的 4 种事务隔离级别【读未提交、读已提交、可重复读、串行化】的最佳实践演示)详解

目录 深入理解分布式事务② ----&#xff1e;分布式事务基础&#xff08;MySQL 的 4 种事务隔离级别【读未提交、读已提交、可重复读、串行化】的最佳实践演示&#xff09;详解1、MySQL 事务基础1-1&#xff1a;MySQL 中 4 种事务隔离级别的区别1-2&#xff1a;MySQL 中 4 种事…

Qt使用OPCUA

假如想在Qt下使用OPCUA通讯&#xff0c;貌似大家都是倾向于使用【qtopcua】这个库。但是在Qt6之前&#xff0c;假如想使用这个库&#xff0c;还得自己编译&#xff0c;比较繁琐。假如想开箱即用&#xff0c;而且没有使用太复杂的功能的话&#xff0c;其实可以直接使用open62541…

2024年最新一线互联网企业高级软件测试工程师面试题大全

1、功能测试 功能测试是游戏测试中跟“玩游戏”最相关的一个环节。 当然这里的“玩”不是要真的让你感受快乐&#xff0c;而是要通过“玩”游戏&#xff0c;发现存在的问题或不合理的地方。因此&#xff0c;这个“玩”的过程基本不会感受到游戏的乐趣。事实上&#xff0c;每一次…

决策树学习笔记

一、衡量标准——熵 随机变量不确定性的度量 信息增益&#xff1a;表示特征X使得类Y的不确定性减少的程度。 二、数据集 14天的打球情况 特征&#xff1a;4种环境变化&#xff08;天气、温度等等&#xff09; 在上述数据种&#xff0c;14天中打球的天数为9天&#xff1b;不…

LVGL移植

Lvgl介绍 LVGL是一个开源的图形库&#xff0c;专为嵌入式系统设计。它提供了丰富的图形元素和功能&#xff0c;可以帮助开发者快速构建现代化的用户界面。LVGL具有跨平台的特性&#xff0c;支持多种操作系统和硬件平台&#xff0c;包括ARM Cortex-M&#xff0c;ESP32&#xff…

基于springboot+vue+Mysql的漫画网站

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

等保测评与信息安全管理体系认证的区别

区别一、标准以及性质 等保测评以《中华人民共和国计算机信息系统安全保护条例》为基础&#xff0c;结合一系列的政策和标准&#xff0c;对信息安全水平进行评估。而安全管理系统的认证&#xff0c;是资讯安全管理系统的一种规范&#xff0c;本身并不具备强制性质。企业可根据…

这么全的权限系统设计方案,不值得收藏吗?

1 为什么需要权限管理 日常工作中权限的问题时时刻刻伴随着我们&#xff0c;程序员新入职一家公司需要找人开通各种权限&#xff0c;比如网络连接的权限、编码下载提交的权限、监控平台登录的权限、运营平台查数据的权限等等。 在很多时候我们会觉得这么多繁杂的申请给工作带…

未来想从事Linux 后台开发,需要学习linux内核吗?

先列出主要观点&#xff0c;有时间再补充细节&#xff1a; “学习Linux内核”对不同的人有不同的含义&#xff0c;学习方法、侧重点、投入的精力也大不相同。我大致分三类&#xff1a;reader、writer、hacker。reader 就是了解某个功能在内核的大致实现 how does it work&…

ZIP压缩输入流(将文件压缩为ZIP文件)

文章目录 前言一、ZIP压缩输入流是什么&#xff1f;二、使用介绍 1.使用方法2.实操展示总结 前言 该篇文章将会介绍如何使用java代码将各种文件&#xff08;文件夹&#xff09;的资源压缩为一个ZIP压缩包。通过java.util包中的ZipOutputStream类来实现。并且需要自定义压缩方法…

记录些AI Agents设计模式和NL2SQL知识

吴恩达分享的四种 自我反思&#xff08;Reflection&#xff09;&#xff1a;可以自我修正&#xff1b;使用工具&#xff08;Tool Use&#xff09;&#xff1a;链接其他系统去做一些事情&#xff0c;比如把电脑里面的未归档文件做好归档&#xff1b;规划&#xff08;Planning&a…