首页 > 其他分享 >QTcpServer和QTcpSocket使用详解

QTcpServer和QTcpSocket使用详解

时间:2023-02-01 22:32:58浏览次数:68  
标签:QTcpServer Widget socket void 详解 QTcpSocket include


QTcpServer和QTcpSocket使用详解


1、基本使用方法

QTcpServer和QTcpSocket的使用是密不可分的,所以两者一块演示使用方法。

QTcpServer常用信号:

  • newConnection()信号,该信号用于处理新接入的连接

QTcpSocket常用信号:

  • disconnected():断开连接后会触发该信号,一般在该信号的槽函数内处理内存清理释放等工作
  • readyRead():数据到达信号,在该信号的槽函数内处理数据接收

补充:如果想要获取远程接入的IP地址端口等信息,可以使用QTcpSocket的peerAddress()函数获取IP地址,peerPort()获取端口。

基于QTcpServer的TCP服务器多接入echo代码demo:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QDebug>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
Q_OBJECT

public:
explicit Widget(QWidget *parent = 0);
~Widget();

private:
Ui::Widget *ui;

private:
QTcpServer* tcpServer;

private slots:
void slotReadyRead();
void slotNewConnected();
};

#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"

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

tcpServer = new QTcpServer(this);
QObject::connect(tcpServer, SIGNAL(newConnection()), this, SLOT(slotNewConnected()));
tcpServer->listen(QHostAddress::Any, 10126);
}

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


void Widget::slotNewConnected()
{
while(tcpServer->hasPendingConnections())
{
QTcpSocket* socket = tcpServer->nextPendingConnection();
QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(slotReadyRead()));
QObject::connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
qDebug("[%s:%d] connected", socket->peerAddress().toString().toStdString().c_str(), socket->peerPort());
}
}

void Widget::slotReadyRead()
{
QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender()); // 取得信号发送者对象
socket->write(socket->readAll()); // 将数据在发送回去
}

2、基于多线程的使用

QTcpServer和QTcpSocket使用详解_Qt处理网络的数据一般不会是单线程处理,因为要更新UI界面且还有任务,不可能让tcpSocket死等接收,正常情况下通过QTcpServer获得新接入的客户端QTcpSocket对象来进行收发数据操作,新接入一个连接就创建一个新的线程去处理,但是这里有一个问题就是 ​​QTcpSocket是不支持跨线程调用的​,哪怕是以引用或者指针的形式传入到子线程中,也是报错跨线程调用!

QTcpServer和QTcpSocket使用详解_Qt要想实现多线程则需要继承QTcpServer去重写​​​incomingConnection​​​函数,在该函数中将​​socketDescriptor​​参数用信号把他发射出来,或者直接在该函数中创建自己的任务处理线程,在线程中使用QTcpSocket类的​​setsetSocketDescriptor​​函数初始化一个socket就可以了。示例代码如下:

#ifndef QMULTITCPSERVER_H
#define QMULTITCPSERVER_H

#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostAddress>

class QMultiTcpServer : public QTcpServer
{
Q_OBJECT

public:
QMultiTcpServer(QObject* parent = nullptr);
virtual ~QMultiTcpServer();

public:
bool listen(const QHostAddress &address, quint16 port);

protected:
void incomingConnection(int socketDescriptor);

signals:
void newConnection(int socketDescriptor);
};

#endif // QMULTITCPSERVER_H
#include "qmultitcpserver.h"

QMultiTcpServer::QMultiTcpServer(QObject* parent):QTcpServer(parent)
{

}

QMultiTcpServer::~QMultiTcpServer()
{

}

void QMultiTcpServer::incomingConnection(int socketDescriptor)
{
emit this->newConnection(socketDescriptor);
}

bool QMultiTcpServer::listen(const QHostAddress &address, quint16 port)
{
return QTcpServer::listen(address, port);
}

示例代码中,我又新增了一个带参数的newConnected信号,目的是为了把socketDescriptor通过信号发射到槽函数中。

然后在主窗体实例化对象:

tcpServer = new QMultiTcpServer(this);
QObject::connect(tcpServer, SIGNAL(newConnection(int)), this, SLOT(slotNewConnected(int)));

对应的槽函数如下:

void Widget::slotNewConnected(int socketDescriptor)
{
QTcpSocket* socket = new QTcpSocket(this);
if(!socket->setSocketDescriptor(socketDescriptor))
{
delete socket;
return;
}

//
// 你可以在这里新建一个处理线程,将socketDescriptor传入处理线程,我这里直接是演示怎么使用
//

QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(slotReadyRead()));
QObject::connect(socket, SIGNAL(disconnected()), this, SLOT(slotDisconnected()));
qDebug("[%s:%d]: connected.", socket->peerAddress().toString().toStdString().c_str(), socket->peerPort());
}

void Widget::slotReadyRead()
{
QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender()); // 取得当前socket对象
QByteArray data = socket->readAll();
qDebug("[%s:%d]:%s", socket->peerAddress().toString().toStdString().c_str(), socket->peerPort(), data.toStdString().c_str());
}

void Widget::slotDisconnected()
{
QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender()); // 取得当前socket对象
socket->close();
qDebug("[%s:%d]: disconnected.", socket->peerAddress().toString().toStdString().c_str(), socket->peerPort());
delete socket;
}

QTcpServer和QTcpSocket使用详解_Qt附上多线程tcp服务器的一个demo,代码功能比较简单,就是只有回显功能。客户端接入后新开一个线程处理数据的发送和接收,执行效果如下:

​https://github.com/wowyyy/QtThreadServer​

QTcpServer和QTcpSocket使用详解_QTcpServer_04



标签:QTcpServer,Widget,socket,void,详解,QTcpSocket,include
From: https://blog.51cto.com/u_15950551/6031950

相关文章

  • 神经网络基础部件-参数初始化详解
    本文内容参考资料为《深度学习》和《解析卷积神经网络》两本书,以及部分网络资料,加以个人理解和内容提炼总结得到。文中直方图的图片来源于参考资料3。一,参数初始化概述......
  • 003dig命令详解
    一、dns解析追踪背景:腾讯云从免费版本转到企业版本后,没有更改DNS服务器指向集群,但实际去看其实已经NS到最新了,如下所示❯dig+tracetaicharge.com;<<>>DiG9......
  • apt-get 详解&&配置阿里源
    转自:https://www.jianshu.com/p/fb337765c2c2apt-get详解&&配置阿里源配置apt-get的下载源1、复制原文件备份sudocp/etc/apt/sources.list/etc/apt/sources.list.ba......
  • Redis的雪崩,击穿,穿透详解-转载
    在今天的互联网里,高并发、大数据量、大流量已经成为了代言词,那么我们的系统也承受着巨大的压力,首当其冲的解决方案就是redis。那么redis使用不当就会产生雪崩、穿透、击穿......
  • 【Flink】详解StreamGraph
    【Flink】详解StreamGraph大家好,我们的gzh是朝阳三只大明白,满满全是干货,分享近期的学习知识以及个人总结(包括读研和IT),跪求一波关注,希望和大家一起努力、进步!!概述没有看上一......
  • LVM逻辑卷详解
    LVM逻辑详卷解[toc]一、LVM的组成1、物理卷-pv物理卷就是指硬盘分区或从逻辑分区具有同样功能的设备(如RAID),是lvm的基本存储逻辑块,它是LVM构建的实际硬件或存储系统。2、卷组......
  • springboot~WebMvcConfigurer详解
    1.前言WebMvcConfigurer配置类其实是Spring内部的一种配置方式,采用JavaBean的形式来代替传统的xml配置文件形式进行针对框架个性化定制,可以自定义一些Handler,Interceptor......
  • pytest.main()参数详解
      importpytestpytest.main(["-n3"])#3个进程并发执行,需要装pytest-xdist库pytest.main(["--collect-only"])#仅仅展......
  • Java并发编程——CompletableFuture详解
    一、简介JDK5引入了Future模式。Future接口是Java多线程Future模式的实现,在java.util.concurrent包中,可以来进行异步计算。 Future模式是多线程设计常用的一种设计模式......
  • Java并发编程——ExecutorCompletionService原理详解
    一、简介在JDK并发包中有这么一个类ExecutorCompletionService,提交任务后,可以按任务返回结果的先后顺序来获取各任务执行后的结果。 该类实现了接口CompletionService:p......