Qt中跨进程Socket通信以及socket跨线程通信
一 QTcpServer 创建流程
- 创建套接字服务器 QTcpServer 对象,
- 通过 QTcpServer 对象设置监听,即:QTcpServer::listen()
- 基于 QTcpServer::newConnection() 信号检测是否有新的客户端连接
- 如果有新的客户端连接调用*QTcpServer::nextPendingConnection() 得到通信的QTcpSocket对象 使用通信的套接字对象 QTcpSocket 和客户端进行通信,readyRead信号
//1.创建server对象
auto server=new QTcpServer(this);
//2.设置服务器监听listen(ipAddr,port)
auto res=server->listen(QHostAddress::Any,8888);//返回监听成功与否,可能存在端口占用情况
//3.基于 QTcpServer::newConnection() 信号检测是否有新的客户端连接
connect(server,&QTcpServer::newConnection,[=]()
{
QTcpSocket* tcpSocket=server->nextPendingConnection();//接收新的客户端连接,用于实际的收发处理 //4.收发处理,
//4.1 当收到数据请求时,tcpSocket会发射readyread信号
connect(tcpSocket,&QTcpSocket::readyRead,[=]()
{
//收到信息请求
auto sMsg=tcpSocket->readAll();
qDebug()<<"Datas from the remote client:"<<sMsg;
});
//4.2 写数据
QByteArray sWriteMsg="Hello Client";
tcpSocket->write(sWriteMsg);
});
二 QTcpSocketClient创建流程
- 创建套接字服务器 QTcpSocket对象,
- 连接服务器,绑定服务器端绑定的IP和端口信息, QAbstractSocket::connectToHost(QHostAddress("127.0.0.1"),8888)
- 检测是否与服务器连接成功,connectToHost() 函数并成功建立连接之后发出 connected() 信号
- 使用通信的套接字对象 QTcpSocket 和客户端进行通信,readyRead信号
//client建立流程
//1.创建通信的套接字类 QTcpSocket 对象
QTcpSocket* tcpSocket=new QTcpSocket(this);
//2.使用服务器端绑定的 IP 和端口连接服务器 QAbstractSocket::connectToHost()
tcpSocket->connectToHost(QHostAddress("127.0.0.1"),8888);
//3.检测是否与服务器连接成功,connectToHost() 函数并成功建立连接之后发出 connected() 信号
connect(tcpSocket,&QTcpSocket::connected,[=]()
{
qDebug()<<"Success to connect to the remote server";
});
//4.使用 QTcpSocket 对象和服务器进行通信,收到数据请求时,tcpSocket会发射readyread信号
connect(tcpSocket,&QTcpSocket::readyRead,[=]()
{
//收到信息请求
auto sMsg=tcpSocket->readAll();
qDebug()<<"Datas from the remote server:"<<sMsg;
});
三 qtSocket多线程通信
模拟客户端发送文件,服务器接收文件为例子,使用多线程方式进行通信,部分代码实现思路。
3.1 socketClient 多线程发送文件实现思路
3.1 .1 SendFile线程任务类实现思路
由于该线程需要完成多个子功能,因此使用moveToThread方式可更加灵活实现多线程
class SendFile : public QObject
//通过 slot 机智定义两个work()函数处理不同的任务功能:
public slots:
//创建线程任务函数
void connectServer();//连接服务器
void sendFileTask();//发送文件
…… //通过signal信号来向主线程发送任务完成情况及线程间的通信
signals:
void connectOk();
void disconnectOk();
void sendCurrentPercen(int n);
3.1.2 主线程中实现思路
//1.创建线程对象
QThread* pThread=new QThread;
//2.创建线程任务对像
SendFile* worker=new SendFile;
//3.将任务对像象添加到线程中
worker->moveToThread(pThread);
//4.启动线程
pThread->start();
//5.信号槽机制关联执行线程任务及线程完成情况
connect(this,&Dialogtest::startConnectServer,worker,&SendFile::connectServer);
connect(this,&Dialogtest::sendFileSignal,worker,&SendFile::sendFileTask); connect(worker,&SendFile::connectOk,this,[=](){//连接成功 });
connect(worker,&SendFile::disconnectOk,this,[=](){ //已断开连接});
connect(worker,&SendFile::sendCurrentPercen,this,[=](int nPercent){ //进度条处理 });
3.2 socketServer多线程接收文件实现思路
3.2.1 TcpServerHelper派生于QTcpServer类
qt中server间跨线程通信时,要保证socket对象的创建与使用线程一致,不能在主线程创建,通过指针传递给子线程进程使用,正确做法是重写socketServer中的incommingConnetction()方法,与客户端连接请求进行设定匹配,即创建一个QTcpServer派生的server类,并重写incomingConnection方法。主要功能仅是 当客户端发起新链接时,该函数会被自动调用,仅向外发送socket描述符。
class TcpServerHelper : public QTcpServer
{
Q_OBJECT
public:
explicit TcpServerHelper(QObject *parent = nullptr);
protected:
//重写incomingConnection,用于多线程通讯,子线程中不能使用主线程中创建的套接字对象
void incomingConnection(qintptr socketDescriptor);
signals:
void newSockDescriptor(qintptr _sock);
}; //.cpp
TcpServerHelper::TcpServerHelper(QObject *parent) : QTcpServer(parent){}
//当客户端发起新链接时,该函数会被自动调用,仅向外发送socket描述符
void TcpServerHelper::incomingConnection(qintptr socketDescriptor)
{
emit newSockDescriptor(socketDescriptor);
}
3.2.2 ReceFile线程任务类
由于该线程仅处理接收数据功能,线程功能比较单一,故派生QThread子类,并重写run()方法来实现多线程
class ReceFile() : public Qthread
class ReceFile(qintptr _socketDesc,QObject* parent=nullptr);
void run();//taskInterface,run函数中要注意使用exec()保持子线程时刻监听,避免子线程退出问题
//通过signal信号来向主线程接收任务完成情况及线程间的通信
signals:
void readDoneSig();
void ReceFile::run()
{
//子线程中创建tcpSocket对象,设置socket描述符,此时将和发起链接的客户端进行通信
m_tcpSocket=new QTcpSocket;
m_tcpSocket->setSocketDescriptor(m_sockDecriptor); QFile* file=new QFile("recv.txt");
file->open(QFile::WriteOnly); //接收数据
connect(m_tcpSocket,&QTcpSocket::readyRead,[=]()
{
static int count=0;
static int total=0;
//第一次读文件信息,文件大小等
if(count==0)
m_tcpSocket->read((char*)&total,4); //读剩余数据
QByteArray readDatas=m_tcpSocket->readAll();
count+=readDatas.size(); //判断数据是否接收完毕
if(count==total)
{
m_tcpSocket->close();
m_tcpSocket->deleteLater();
m_tcpSocket=nullptr;
file->close();
file->deleteLater(); emit readDoneSig();
} }); //子线程进入事件循环,保持时刻监听
exec();
}
3.2.3 主线程
主线程中当客户端发起连接请求时才开启子线程工作,即:
connect(m_tcpServer,&TcpServerHelper::newSockDescriptor,this,[=](qintptr _sockDesc)
{
//创建子线程,并启动线程
ReceFile* recvThread=new ReceFile(_sockDesc);
recvThread->start(); //资源释放,善后工作
connect(recvThread,&ReceFile::readDoneSig,[=]()
{
//子线程退出
recvThread->exit();
recvThread->wait();
recvThread->deleteLater();
});
});
3.3 关于Qt中socket跨线程通讯问题
主线程创建的socket套接字对象,传入到子线程中,可能因为qt版本或者windows平台问题,日志可能会报主线程创建的socket对象不能在子线程工作。另外,一个server对应一个client线程,可能没有问题出现,但是QTcpServer若为每个客户端分配一个独立线程【典型的如聊天室】,必须重写 IncomingConnection()函数。 Qt帮助文档:不能在线程中调用QTcpServer自动创建的QTcpSocket对象,并且在incomingConnection()的帮助中有提到,若将客户端的连接传入单独的线程,则QTcpSocket对象必须创建在线程中,socket对象的创建通过重写incomingConnection()函数实现。
QTcpServer类的工作机制:
- 在有传入连接时,QTcpServer会创建一个与客户端匹配的socket,并返回一个指向socket内存的socketDescriptor(socket描述符),在QT中该描述符是qintptr类型的。
- 然后,QTcpServer会自动调用incomingConnection()函数,该函数接收这个socketDescriptor。
incomingConnection源码实现:
- 首先,创建了一个QTcpSocket对象,
- 然后,调用QTcpSocket::setSocketDescriptor(qintptr socketDescriptor),设置socket描述符;
- 最后,调用addPendingConnection(QTcpSocket * socket),将创建的QTcpSocket对象指针挂起在已创建列表中,该行为可终止waitForNewConnection()的阻塞,并且用户可以通过调用nextPendingConnection()函数获得这个QTcpSocket对象指针。注意:在线程版的incomingConnection()函数中,可以省略这步addPendingConnection()的调用,因为不再需要通过nextPendingConnection()函数来获得socket指针了。 重写incomingConnection()函数: 重写函数需要创建一个QTcpServer的派生类,另外还需创建一个线程类。
Qt中跨进程Socket通信以及socket跨线程通信的更多相关文章
- ZeroMq实现跨线程通信
ZeroMq实现跨线程通信 之前在技术崇拜的技术经理指导下阅读了ZeroMq的基础代码,现在就将阅读的心得与成果记录一下,并重新模仿实现了一下经理的异步队列. 1.对外接口 //主要接口(1)void ...
- Zenject与UniRx结合实现跨线程通信Signal
修改Zenject下ProfileBlock.cs源码, 取消有关UnityEngine.Profiling.Profiler的代码. 然后使用Zenject的Signal: // 定义Signal ...
- Qt自带的阴影类、跨线程问题汇总、hover相关、全屏轮子,一些思考。
一点思考:故事的结局重不重要? 我语文不好,但是我数学不好. 我数学不好,但是我英语不好. 我英语不好,但是我物理不好. 我物理不好,但是我化学不好. 我化学不好,但是我历史不好. 我历史不好,但是我 ...
- samephore()信号量跨线程通信
samephore1: #include <stdio.h> #include <stdlib.h> #include <Windows.h> ] = " ...
- JNI加载Native Library 以及 跨线程和Qt通信
Part1 Java Native Interface-JNI-JAVA本地调用 JNI标准是Java平台的一部分, 允许Java代码和其他语言进行交互; 开始实现-> Step 1) 编写Ja ...
- Android中线程通信的方式
Android 跨线程通信 android 中是不允许在主线程中进行 网络访问等事情的因为UI如果停止响应5秒左右的话整个应用就会崩溃,到Android4.0 以后 Google强制规定,与网络相关的 ...
- JAVA多线程提高二:传统线程的互斥与同步&传统线程通信机制
本文主要是回顾线程之间互斥和同步,以及线程之间通信,在最开始没有juc并发包情况下,如何实现的,也就是我们传统的方式如何来实现的,回顾知识是为了后面的提高作准备. 一.线程的互斥 为什么会有线程的互斥 ...
- java多线程——线程通信
一.线程通信目标 1.线程通信的目标是使线程间能够互相发送信号 2.线程通信使线程能够等待其他线程的信号 二.几种方式 1.通过共享对象 2.忙等待 线程 B 运行在一个循环里,以等待信号 (不释放c ...
- Java多线程-同步:synchronized 和线程通信:生产者消费者模式
大家伙周末愉快,小乐又来给大家献上技术大餐.上次是说到了Java多线程的创建和状态|乐字节,接下来,我们再来接着说Java多线程-同步:synchronized 和线程通信:生产者消费者模式. 一.同 ...
- Android 进阶12:进程通信之 Socket (顺便回顾 TCP UDP)
不要害怕困难,这是你进步的机会! 读完本文你将了解: OSI 七层网络模型 TCPIP 四层模型 TCP 协议 TCP 的三次握手 TCP 的四次挥手 UDP 协议 Socket 简介 Socket ...
随机推荐
- PostGIS之Geometry
1. 概述 PostGIS 是PostgreSQL数据库一个空间数据库扩展,它添加了对地理对象的支持,允许在 SQL 中运行空间查询 PostGIS官网:About PostGIS | PostGIS ...
- Angular UI库
1.angular 使用 bootstrap 安装bootstrap npm install bootstrap --save 安装bootstrap-icons npm i bootstrap-ic ...
- Linux命令使用时路径存在空格、特殊符号
https://blog.csdn.net/Homewm/article/details/102935965 Linux命令使用时路径存在空格.特殊符号(如-.@等等)如何处理呢? 再如可以转义的字符 ...
- gridfs + nginx + mongodb 实现图片服务器
项目预览网址 : http://trans.waibaobao.cn/file/pics 安装:前提安装mongodb 作为文件储存库 1)nginx-gridfs安装 a.安装所用依赖包 yum - ...
- Windows 隐藏 远程桌面(连接栏)
当我们在使用远程桌面控制的时候,远程桌面工具栏遮挡视线很烦人.这时候就很有必要隐藏了! 1.全屏时显示连接栏 勾选去掉 这样子远程桌面上方的连接栏就消失了. 那么我们怎么打开呢?所以就要写下来记住了. ...
- ionic混合开发总结之调用手机相机
整理一下,给接触ionic的伙伴们一些参考,少走弯路. 调用手机的前提是已经成功创建了项目. 首先,要下载两个插件,一个是 cordova-plugin-camera,是调用相机的插件,还有一个是Ng ...
- 微信电脑版 v3.9.2.12 绿色便携版
修改历史: 2023.03.01:自改官方 3.9.2.12 最新正式版本2023.01.31:自改官方 3.9.0.28 最新正式版本2023.01.11:自改官方 3.9.0.21 最新正式版本- ...
- 代码随想录 day0 博客怎么写
前言 2.25日开始记录自己的博客生涯以及代码随想录训练营的每日内容 一.题目链接怎么找?怎么设置连接? 力扣题目链接1:力扣 二.正文怎么写? 二分查找 算法思路: 二分查找需要保证数组为有序数组同 ...
- react项目打包后点击index.html页面出现空白
当本地打包后的文件,直接通过文件路径访问,出现空白或者,提示打包后的build内的js,css文件路径错误,有以下两种方式 方式一(无网络限制的情况下使用): 1.全局安装serve启动本地服务: n ...
- kubeSphere+kubernetes 集群更新证书
模拟问题点 使用kubernetes时错误提示 yang@master:~$ kubectl get nodes Unable to connect to the server: x509: cert ...