使用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;  //socketQLabel  *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();//本机IPthis->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_OBJECTpublic:socket(QObject *parent=nullptr);~socket();
public slots:void connectToHost(QString hostName, quint16 port);void send_msg();
private:QTcpSocket* tcpClient;  //socketQTimer* 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.mzph.cn/pingmian/4400.shtml

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

相关文章

单模与多模光纤:深入解析与应用

在现代通信系统中&#xff0c;光纤技术是不可或缺的一部分&#xff0c;它以其高速度和大容量传输数据而闻名。光纤主要分为两种类型&#xff1a;单模光纤&#xff08;Single-Mode Fiber, SMF&#xff09;和多模光纤&#xff08;Multimode Fiber, MMF&#xff09;。这两种光纤在…

Matplotlib是什么?

一、Matplotlib是什么&#xff1f; Matplotlib是一个Python语言的2D绘图库&#xff0c;它非常广泛地用于数据的可视化。以下是一些主要特点&#xff1a; 多功能性&#xff1a;它允许用户创建各种静态、动态或交互式的图表&#xff0c;如线图、散点图、直方图等。跨平台性&…

计算机视觉——使用OpenCV GrabCut算法从图像中移除背景

GrabCut算法 GrabCut算法是一种用于图像前景提取的技术&#xff0c;由Carsten Rother、Vladimir Kolmogorov和Andrew Blake三位来自英国剑桥微软研究院的研究人员共同开发。该技术的核心目标是在用户进行最少交互操作的情况下&#xff0c;自动从图像中分割出前景对象。 在Gra…

机器学习/算法工程师面试题目与答案-数学基础部分

机器学习/算法工程师面试题目--数学基础部分 一、数学基础1、微积分SGD,Momentum,Adagard,Adam原理L1不可导的时候该怎么办sigmoid函数特性 2、统计学&#xff0c;概率论求 Max(a, b) 期望拿更长的玫瑰花的最好策略最大化工作天数的员工数切比雪夫不等式随机截成三段组成三角形…

信号分解 | RLMD(鲁棒性局部均值分解)-Matlab

分解效果 RLMD(鲁棒性局部均值分解) RLMD(鲁棒性局部均值分解)-Matlab 代码实现 % %% 清除所有变量 关闭窗口 clc clear all close all%% 导入数据 % data = xlsread(Data.xlsx);%% 输入信号%% RLMD分解 %参数进行设置 % options.display =

SpringCloud系列(20)--Ribbon的简介及使用

1、Ribbon的简介 Spring Cloud Ribbon是基于Netflix Ribboh实现的一套客户端负载均衡的工具&#xff0c;简单的说&#xff0c;Ribbon是Netflix发布的开源项目&#xff0c;主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项如连接超时…

ETL中元数据处理的方式

ETLCloud平台是用于处理从数据抽取、转换、加载到持续数据捕获等一系列数据管理活动。除此之外还支持微服务治理与快速开发&#xff0c;并且具备数据库监听功能&#xff0c;能够以不同的方式监听并同步源数据库表数据到目标系统&#xff0c;比如直接传输、通过ETL流程处理或者传…

交直流充电桩检测的基础知识

交直流充电桩检测是电动汽车充电设施的重要组成部分&#xff0c;其目的是确保充电桩的正常运行&#xff0c;保障电动汽车的安全充电。以下是关于交直流充电桩检测的一些基础知识。 我们需要了解什么是交直流充电桩&#xff0c;简单来说&#xff0c;交直流充电桩是一种为电动汽车…

二维数组打印菱形(C语言)

一、N-S流程图&#xff1b; 二、运行结果&#xff1b; 三、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;char arr[5][5] { { , , *, , }, { , *, *, *, },{*, *, *, *, *}, { , *, *, *, …

使用NGINX做局域网内 浏览器直接访问链接 拓展外网链接访问本地

达成目的功能&#xff1a; 在本地服务的一个文件路径下&#xff0c;局域网内用ip和路径名访问到对应的地址&#xff1b;如 10.5.9.0/v1 即可访问到 某个固定本地地址目录 V1下&#xff0c;名为index.html的文件。前言 NGINX 是一个非常流行的开源 Web 服务器和反向代理服务器…

社交媒体数据恢复:Reddit

Reddit是一個娛樂、社交及新聞網站&#xff0c;註冊使用者可以將文字或連結在網站上發布&#xff0c;使它基本上成為了一個電子佈告欄系統。註冊使用者可以對這些貼文進行投票&#xff0c;結果將被用來進行排名和決定它在首頁或子頁的位置。網站上的內容分類被稱為「subreddit」…

Springboot+Vue项目-基于Java+MySQL的智慧校园管理系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…

【研发管理】产品经理知识体系-产品设计与开发工具

导读&#xff1a;产品设计与开发工具的重要性体现在多个方面&#xff0c;它们对于产品的成功开发、质量提升以及市场竞争力都具有至关重要的影响。产品设计工具可以帮助设计师更高效地创建和优化产品原型。开发工具在产品开发过程中发挥着至关重要的作用。产品设计与开发工具还…

PotatoPie 4.0 实验教程(25) —— FPGA实现摄像头图像直方图均衡变换

图像的直方图均衡是什么&#xff1f; 图像的直方图均衡是一种用于增强图像对比度的图像处理技术。在直方图均衡中&#xff0c;图像的像素值被重新分配&#xff0c;以使得图像的直方图变得更均匀&#xff0c;即各个像素值的分布更加平衡。这意味着直方图中每个像素值的频率大致…

AMBA-CHI协议详解(二)

《AMBA 5 CHI Architecture Specification》 文章目录 2.1 Channels综述2.2 Channel域段2.2.1 request fields2.2.2 Response fields2.2.3 Snoop request fields2.2.4 Data fields 2.3 事务结构2.3.1 Read transactions2.3.1.1 Allocating Read2.3.1.2 Non-allocating Read 2.…

Spring Boot 的文件配置

SpringBoot的配置文件,有三种格式 1.properties 2.yaml 3.yml(yaml的简写) 这里主要介绍1和3格式的。 在项目中,同时存在properties和yml配置文件, properties的优先级更高 同时存在时,两个文件都生效 如果两个文件中,都包含同一个配置,以properties为主。 properties的配置…

深入解析AI绘画算法:从GANs到VAEs

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

FebHost:摩洛哥.ma域名注册介绍,规则有哪些?

摩洛哥国家域名介绍 摩洛哥是位于非洲西北部的一个国家&#xff0c;北部和西部面向地中海和大西洋&#xff0c;东部和南部则与阿尔及利亚、西撒哈拉和毛里塔尼亚接壤。摩洛哥的首都是拉巴特&#xff0c;但最大城市是卡萨布兰卡。摩洛哥的官方语言是阿拉伯语和柏柏尔语&#xf…

使用 Python 和 DirectShow 从相机捕获图像

在 Python 中使用 OpenCV 是视觉应用程序原型的一个非常好的解决方案,它允许您快速起草和测试算法。处理从文件中读取的图像非常容易,如果要处理从相机捕获的图像,则不那么容易。OpenCV 提供了一些基本方法来访问链接到 PC 的相机(通过对象),但大多数时候,即使对于简单的…

Github创建远程仓库(项目)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…