使用QTcpSocket

news2025/3/11 0:14:09

(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)

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

11 - 在k8s官方文档上,经常搜索不到内容的问题

使用k8s官方文档时&#xff0c;会出现首页可以正常打开&#xff0c;但是输入搜索关键字之后&#xff0c;搜索不到内容的情况&#xff0c;如下图&#xff1a; 这是由于相关搜索组件被墙的原因&#xff0c;处理方法如下&#xff1a; 谷歌浏览器&#xff1a; 火狐浏览器&#x…

Epic游戏商店再送大作,兽人必须死3即将免费领取

Epic游戏商店再送大作&#xff01;兽人必须死3即将免费领取 圣诞节过后&#xff0c;Epic游戏商店一直在送出精心制作的小游戏或者在小圈子里备受热议的作品。虽然之前送过的游戏如《天外世界》和《幽灵行者》等名气不小&#xff0c;但对于一直在“白嫖”的玩家们来说&#xff0…

采用php vue2 开发的一套医院安全(不良)事件管理系统源码(可自动生成鱼骨图)

采用php vue2 开发的一套医院安全&#xff08;不良&#xff09;事件管理系统源码&#xff08;可自动生成鱼骨图&#xff09; 医院安全&#xff08;不良&#xff09;事件管理系统采用无责的、自愿的填报不良事件方式&#xff0c;有效地减轻医护人员的思想压力&#xff0c;以事件…

【Go语言快速上手(四)】面向对象的三大特性引入

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Go语言专栏⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多Go语言知识   &#x1f51d;&#x1f51d; GO快速上手 1. 前言2. 初识GO中的结构…

记内网http洪水攻击,导致网页无法访问一事

事由 最近两日&#xff0c;部分同事在访问税纪云平台时&#xff0c;登录跳转页面频繁转圈、要么就是出现无法连接的错误提示。 无法访问此页面 已重置连接。 请尝试: 检查连接 检查代理和防火墙 运行 Windows 网络诊断经过以下几方面的排查&#xff0c;无果。 后续通过检查…

【Node.js】02 —— Path模块全解析

&#x1f31f;Node.js之Path模块探索&#x1f308; &#x1f4da;引言 在Node.js的世界中&#xff0c;path模块就像一把万能钥匙&#x1f511;&#xff0c;它帮助我们理解和操作文件与目录的路径。无论你是初入Node.js殿堂的新手&#xff0c;还是久经沙场的老兵&#xff0c;理…

Docker容器概念介绍与基本管理

前言 在软件开发和部署环境中&#xff0c;使用 Docker 等容器技术可以帮助团队实现快速、一致、可靠的应用程序部署&#xff0c;提高开发效率和应用程序的可移植性。 目录 一、虚拟化产品介绍 1. 云服务模型 1.1 IaaS 1.2 PaaS 1.3 SaaS 1.4 DaaS 2. 产品介绍 2.1 虚…

【八股】Spring篇

why Spring? 1.使用它的IOC功能&#xff0c;在解耦上达到了配置级别。 2.使用它对数据库访问事务相关的封装。 3.各种其他组件与Spring的融合&#xff0c;在Spring中更加方便快捷的继承其他一些组件。 IoC和DI &#x1f449;IOC是Inversion of Control的缩写&#xff0c;“…

Nginx 四层和七层代理区别、配置

四层&#xff1a;通过报文中的目标地址和端口&#xff0c;加上负载均衡设备设置的服务器选择方式&#xff0c;决定最终选择的内部服务器&#xff0c;使用tcp、udp协议。 七层&#xff1a;"内容交换"&#xff0c;通过报文中真正有意义的应用层内容&#xff0c;加上负…

ETLCloud平台组件模版的使用技巧

ETL工具介绍 在ETLCloud平台中配备了各种不同的组件、模板、规则&#xff0c;用户可运用不同类型的组件来实现想要的业务流程。接下来直接进入平台组件模板的使用技巧说明吧。 使用技巧 1.组件复制 平时在使用的时候&#xff0c;如果遇到要用到一个组件&#xff0c;需要再来…

创建一个空的maven项目,整合SpringBoot和Redis

创建一个空的maven项目&#xff0c;整合SpringBoot和Redis 创建空的maven项目 在最新版的idea中创建maven项目的时候会让选择模板 如下图&#xff1a; 我们选择quickstart快速开始模板&#xff0c;quickstart快速开始模板创建的maven项目里面什么都不带&#xff0c;只有一个…

【机器学习】集成学习---投票法(Voting)

一、引言 集成学习&#xff08;Ensemble Learning&#xff09;是机器学习领域中的一种重要策略&#xff0c;它通过结合多个模型的预测结果来提高整体性能。在单个模型容易过拟合或欠拟合的情况下&#xff0c;集成学习能够通过综合多个模型的优点来减少这种风险&#xff0c;从而…

javaWeb项目-房屋房租租赁系统功能介绍

项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#xff1a;Vue、ElementUI 关键技术&#xff1a;springboot、SSM、vue、MYSQL、MAVEN 数据库工具&#xff1a;Navicat、SQLyog 1、JSP技术 JSP(Jav…

企业如何创建自己的维基百科词条?难吗?

维基百科词条创建与编辑概述 &#xff08;Wikipedia&#xff09;是全球网络上最大且最受大众欢迎的参考工具&#xff0c;其内容丰富、更新及时&#xff0c;被广泛应用于学术研究、商业决策和普通大众的查询需求。词条的创建与编辑对于很多人来说可能是一个挑战&#xff0c;但实…

echarts树图-实现拓扑图效果

使用echarts树图来实现拓扑图效果&#xff0c;其效果如下&#xff1a; 代码如下&#xff1a; const data {name: XXX公司,children: [{name: 网络主机,children: [{name: 普通路由器,children: [{name: 智能网关},{name: 192.168.1.0/24}]}]},{name: 企业路由器},{name: 三…

Linux 系统IO函数之lseek函数

lseek函数 要点&#xff1a; off_t lseek(int fd, off_t offset, int whence); seek 寻找 man 2 lseek标准C库的函数 #include <stdio.h> int fseek(FILE *stream, long offset, int whence);Linux系统函数 #include <sys/types.h> #include <unistd.h> off…

深度解析 Spring 源码:揭秘BeanFactory 之谜

文章目录 一、认识BeanFactory1.1 BeanFactory的概述1.2 BeanFactory与 ApplicationContext的区别 二、BeanFactory源码解读2.1 BeanFactory 接口2.1.1 getBean()2.1.2 containsBean()2.1.3 isSingleton() 2.2 DefaultListableBeanFactory 类2.2.1 registerBeanDefinition()2.2…

书生·浦语大模型实战营之Llama 3 高效部署实践(LMDeploy 版)

书生浦语大模型实战营之Llama 3 高效部署实践&#xff08;LMDeploy 版&#xff09; 环境&#xff0c;模型准备LMDeploy chatTurmind和Transformer的速度对比LMDeploy模型量化(lite)LMDeploy服务(serve) 环境&#xff0c;模型准备 InternStudio 可以直接使用 studio-conda -t …

mmcv bug记录

图像分类任务要用到mmcv框架&#xff0c;记录遇到的问题 1. Can‘t import build_from_cfg from mmcv. 解决命令&#xff1a;pip install openmim && mim install mmcv-full 2. python分布式训练 解决方案&#xff1a; 租用多张A40卡&#xff0c;执行下述命令&…

C# Solidworks二次开发:访问平面、曲面相关API详解

大家好&#xff0c;今天要介绍的是关于平面、曲面相关的API。 下面是相关的API: &#xff08;1&#xff09;第一个为ISurfacePlanarFeatureData&#xff0c;这个API的含义为允许访问平面表面特征&#xff0c;下面是官方的具体解释&#xff1a; 下面是官方使用的例子&#xff…