Qt笔记-QTcpSocket跨线程调用(官方推荐方法,非百度烂大街方法)

8 篇文章 2 订阅

TCP服务端的经典案例中有个例子,就是当收到TCP客户端连接后,线程池直接开一个线程然后把这个socket指针传到线程里面,依靠新开的线程进程业务处理。

但在Qt里面使用这个方式后,会报一个QTcpSocket不能跨线程调用的问题。

问题描述是这样的:

QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread

查了下百度,都是n年前的技术(本博文写于2021-08-11 09:15:25,此博文发布到网上应该是1个月以后,笔记太多了,每星期公布6篇笔记),用信号与槽机制将业务处理放到新线程中,TCP操作用信号让以前的线程发送数据,通过这种方式解决问题!但如果这样做,代码就不够优雅了,甚至还有点烂。一个新技术框架和老技术做对比,应该是取其精华去其糟粕,而不是越来越复杂。不然这个新技术将毫无意义。

花了半天时间查阅了官方资料,最后得出了QTcpSocket跨线程调用的方式。

首先继承QTcpServer重写incomingConnection(qintptr handle)

 

当这个handle此时套接字的描述符号。把这个传给线程,子线程生成一个QTcpScoket然后利用setSocketDescriptor使得这个socket获得到收发数据的能力。

实例如下:

QTcpServer相关:

void HttpsServer::incomingConnection(qintptr socketDescriptor)
{
    QThreadPool::globalInstance()->start(new HttpsThread(socketDescriptor));
}

QRunnable相关:

HttpsThread::HttpsThread(qintptr descriptor)
{
    m_socketDescriptor = descriptor;
}

这个m_socketDescriptor直接为int型就可以了。

这样run()中调用setSocketDescriptor,进行读写操作就不会有跨线程的问题了。

void HttpsThread::run()
{
    QTcpSocket tcpSocket;
    if(!tcpSocket.setSocketDescriptor(m_socketDescriptor)) {

        qDebug() << "tcpSocket.setSocketDescriptor(m_socketDescriptor) failed";
        return;
    }

    tcpSocket.write("Hello Wold");

    tcpSocket.disconnectFromHost();
    tcpSocket.waitForDisconnected();
}
好的,你的问题是关于 QTcpSocket 自动重连的。为了实现 QTcpSocket 的自动重连,可以使用 QTimer 和 QTcpSocket 的 error() 信号。具体步骤如下: 1. 设置一个 QTimer,用于定时重连 QTcpSocket。 2. 创建 QTcpSocket,并连接它的 error() 信号到一个槽函数中。 3. 在槽函数中判断 error() 信号传递的错误码是否为 QAbstractSocket::RemoteHostClosedError。 4. 如果错误码为 QAbstractSocket::RemoteHostClosedError,则说明连接已经断开,重连 QTcpSocket。 5. 如果错误码为其他值,则说明连接出现了其他错误,不再重连。 下面是示例代码: ```cpp class MySocket : public QObject { Q_OBJECT public: explicit MySocket(QObject *parent = nullptr); private slots: void reconnect(); void onSocketError(QAbstractSocket::SocketError error); private: QTcpSocket *m_socket; QTimer *m_timer; }; MySocket::MySocket(QObject *parent) : QObject(parent) { m_socket = new QTcpSocket(this); connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onSocketError(QAbstractSocket::SocketError))); m_timer = new QTimer(this); connect(m_timer, SIGNAL(timeout()), this, SLOT(reconnect())); } void MySocket::onSocketError(QAbstractSocket::SocketError error) { if (error == QAbstractSocket::RemoteHostClosedError) { m_timer->start(5000); // 5s 后重连 } else { qDebug() << "Socket error: " << m_socket->errorString(); } } void MySocket::reconnect() { m_socket->connectToHost("127.0.0.1", 1234); if (m_socket->waitForConnected(5000)) { m_timer->stop(); } } ``` 在上面的示例中,如果 QTcpSocket 的 error() 信号传递的错误码为 QAbstractSocket::RemoteHostClosedError,则启动定时器,在 5 秒后重连 QTcpSocket。如果连接成功,则停止定时器。如果连接出现其他错误,则输出错误信息。
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT1995

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值