美文网首页
QTcpSocket

QTcpSocket

作者: 诸事圆成 | 来源:发表于2022-12-20 20:34 被阅读0次

注意点

QTcpSocket是Qt框架中的网络通信类,它使用QSocketNotifier实现异步通信。在Qt中,QSocketNotifier是一个用于处理套接字事件的类。
在使用QTcpSocket时,如果将读写套接字的操作放在线程中进行,则可能会出现"QSocketNotifier: socket notifiers cannot be enabled from another thread"的错误。这是因为QSocketNotifier是线程不安全的,它只能在创建它的线程中使用。
要解决这个问题,你可以使用Qt的信号和槽机制在线程之间传递数据。
具体步骤如下:
1.在主线程中创建QTcpSocket对象
2.在线程中创建一个新的QObject对象
3.将QObject对象的信号连接到QTcpSocket的readyRead()信号
4.在QObject对象的槽函数中读取数据
5.将QObject对象移动到线程中
这样,当QTcpSocket可以读取数据时,它会发出readyRead()信号,这将触发QObject对象的槽函数,从而在线程中读取数据。

#include <QTcpSocket>
#include <QDataStream>

class TcpClient : public QObject
{
    Q_OBJECT

public:
    TcpClient(QObject *parent = nullptr);
    ~TcpClient();

    void connectToServer(const QString &hostName, quint16 port);
    void disconnectFromServer();
    void sendData(const QByteArray &data);

signals:
    void connected();
    void disconnected();
    void error(QAbstractSocket::SocketError socketError);
    void dataReceived(const QByteArray &data);

private slots:
    void onConnected();
    void onDisconnected();
    void onError(QAbstractSocket::SocketError socketError);
    void onReadyRead();

private:
    QTcpSocket *m_tcpSocket;
    QDataStream m_in;
};

TcpClient::TcpClient(QObject *parent) : QObject(parent)
{
    m_tcpSocket = new QTcpSocket(this);
    m_in.setDevice(m_tcpSocket);
    m_in.setVersion(QDataStream::Qt_5_15);

    connect(m_tcpSocket, &QTcpSocket::connected, this, &TcpClient::onConnected);
    connect(m_tcpSocket, &QTcpSocket::disconnected, this, &TcpClient::onDisconnected);
    connect(m_tcpSocket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error), this, &TcpClient::onError);
    connect(m_tcpSocket, &QTcpSocket::readyRead, this, &TcpClient::onReadyRead);
}

TcpClient::~TcpClient()
{
    m_tcpSocket->disconnectFromHost();
    m_tcpSocket->waitForDisconnected();
}

void TcpClient::connectToServer(const QString &hostName, quint16 port)
{
    m_tcpSocket->connectToHost(hostName, port);
}

void TcpClient::disconnectFromServer()
{
    m_tcpSocket->disconnectFromHost();
}

void TcpClient::sendData(const QByteArray &data)
{
    m_tcpSocket->write(data);
}

void TcpClient::onConnected()
{
    emit connected();
}

void TcpClient::onDisconnected()
{
    emit disconnected();
}

void TcpClient::onError(QAbstractSocket::SocketError socketError)
{
    emit error(socketError);
}

void TcpClient::onReadyRead()
{
    QByteArray data;
    m_in >> data;
    emit dataReceived(data);
}

如何必须这样做 【new QTcpSocket在主线程,读写socket在另外的线程】

如果你必须将socket的读写操作放在线程中进行,则可以使用Qt的事件机制来解决这个问题。
在Qt中,可以使用QCoreApplication::postEvent()函数在主线程中发送事件,并使用QObject::event()函数在线程中处理事件。
具体步骤如下:
1.在主线程中创建QTcpSocket对象
2.在线程中创建一个新的QObject对象
3.在主线程中使用QCoreApplication::postEvent()函数发送事件
4.在QObject对象的event()函数中读取数据
5.将QObject对象移动到线程中
这样,当QTcpSocket可以读取数据时,主线程会发送事件到线程中,并触发QObject对象的event()函数,从而在线程中读取数据。



#include <QTcpSocket>
#include <QThread>
#include <QObject>
#include <QCoreApplication>

class SocketEvent : public QEvent
{
public:
    SocketEvent(QTcpSocket *socket)
        : QEvent(QEvent::Type(QEvent::User + 1)), m_socket(socket)
    {
    }

    QTcpSocket *socket() const
    {
        return m_socket;
    }

private:
    QTcpSocket *m_socket;
};

class SocketThread : public QThread
{
    Q_OBJECT

public:
    SocketThread(QTcpSocket *socket)
        : m_socket(socket)
    {
    }

protected:
    void run() override
    {
        // 创建QObject对象
        QObject *receiver = new QObject;

        // 将QObject对象移动到线程中
        receiver->moveToThread(this);

        // 开始执行线程
        QThread::exec();
    }

private:
    QTcpSocket *m_socket;
}

// 在QObject对象的event()函数中读取数据
bool QObject::event(QEvent *event)
{
    if (event->type() == QEvent::User + 1) {
        SocketEvent *socketEvent = static_cast<SocketEvent *>(event);
        QTcpSocket *socket = socketEvent->socket();

        QByteArray data = socket->readAll();
        // 处理读取的数据

        return true;
    }

    return QObject::event(event);
}


int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    // 在主线程中创建QTcpSocket对象
    QTcpSocket *socket = new QTcpSocket;

    // 创建SocketThread对象
    SocketThread *thread = new SocketThread(socket);

    // 开始执行线程
    thread->start();

    // 连接QTcpSocket的readyRead()信号
    QObject::connect(socket, &QTcpSocket::readyRead, [thread, socket]() {
        // 使用QCoreApplication::postEvent()函数发送事件
        QCoreApplication::postEvent(thread, new SocketEvent(socket));
    });
    return app.exec();
}

相关文章

网友评论

      本文标题:QTcpSocket

      本文链接:https://www.haomeiwen.com/subject/ncoyqdtx.html