繁体   English   中英

带QTcpSocket,QTcpServer和QTimer的定期发送

[英]Periodic sending w/ QTcpSocket, QTcpServer & QTimer

我在这里有一个奇怪的行为,寻求帮助。 好了!

问题

我有一个称为DataReceiver的接收类,它使用QTcpServer和QTcpSocket,并且我有DataSender类通过QTcpSocket对其进行馈送。 我定期发送数据,并触发带有QTimer的“发送”插槽。

但是,经过几次迭代后,Feed停顿了,不再是周期性的。 我真的不明白发生了什么。

我已经在接收器端确认了带有终端打印的问题。

编码

datasender.cpp

// Con/Destructors
DataSender::DataSender(QObject *parent) :
    QObject(parent),
    mTcpSocket(new QTcpSocket(this)),
    mDestinationAddress("127.0.0.1"),
    mDestinationPort(51470),
    mTimer(new QTimer(this))
{
    connectToHost();

    connect(mTimer, SIGNAL(timeout(void)), this, SLOT(sendPeriodicData()));
    mTimer->start(1000);
}

DataSender::~DataSender(){
    mTcpSocket->disconnectFromHost();
    mTcpSocket->waitForDisconnected();
    delete mTcpSocket;
}

// Network Management
bool DataSender::connectToHost(void){
    connect(mTcpSocket, SIGNAL(connected()), this, SLOT(onConnect()));
    connect(mTcpSocket, SIGNAL(disconnected()), this, SLOT(onDisconnect()));
    connect(mTcpSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(onBytesWritten(qint64)));

    qDebug() << "connecting...";

    mTcpSocket->setSocketOption(QAbstractSocket::KeepAliveOption, true);
    mTcpSocket->setSocketOption(QAbstractSocket::WriteOnly);
    mTcpSocket->connectToHost(getDestinationAddress(), getDestinationPort());

    if(!mTcpSocket->waitForConnected(1000))
    {
        qDebug() << "Error: " << mTcpSocket->errorString();
        return false;
    }

    // Setting meteo data to send
    mMeteoData.messageID    = METEO_MESSAGE;
    mMeteoData.temperature  = 5.5;
    mMeteoData.pressure     = 10.2;
    mMeteoData.humidity     = 45.5;

    // Setting positiondata to send
    mPositionData.messageID = POSITION_MESSAGE;
    mPositionData.north     = 120.3;
    mPositionData.pitch     = 1.5;
    mPositionData.roll      = 2.5;
    mPositionData.yaw       = 3.5;
    mPositionData.a_x       = 30.5;
    mPositionData.a_y       = 40.5;
    mPositionData.a_z       = 50.5;

    return true;
}

void DataSender::sendData(void) const{
    QByteArray lData("Hello, this is DataSender ! Do you copy ? I repeat, do you copy ?");

    if(mTcpSocket->state() == QAbstractSocket::ConnectedState)
    {
        mTcpSocket->write(lData);
        mTcpSocket->waitForBytesWritten();
    }
}

void DataSender::sendData(const QByteArray &pData) const{
    //QByteArray lData("Hello, this is DataSender ! Do you copy ? I repeat, do you copy ?");

    if(mTcpSocket->state() == QAbstractSocket::ConnectedState)
    {
        mTcpSocket->write(pData);
        mTcpSocket->waitForBytesWritten();
        mTcpSocket->flush();
        //usleep(1000);
    }
}

// Getters
QString DataSender::getDestinationAddress(void) const{
    return mDestinationAddress;
}

unsigned int DataSender::getDestinationPort(void) const{
    return mDestinationPort;
}

// Setters
void DataSender::setDestinationAddress(const QString &pDestinationAddress){
    mDestinationAddress = pDestinationAddress;
}

void DataSender::setDestinationPort(const unsigned int &pDestinationPort){
    mDestinationPort = pDestinationPort;
}

// Public Slots
void DataSender::onConnect(){
    qDebug() << "connected...";
}

void DataSender::onDisconnect(){
    qDebug() << "disconnected...";
}

void DataSender::onBytesWritten(qint64 bytes){
    qDebug() << bytes << " bytes written...";
}

void DataSender::sendPeriodicData(void){
    mTcpSocket->
    // Changing data for testing
    mPositionData.north += 10;
    mPositionData.north = std::fmod(mPositionData.north, 360);
    mMeteoData.temperature += 10;
    mMeteoData.temperature = std::fmod(mMeteoData.temperature, 500);

    // Declaring QByteArrays
    QByteArray lMeteoByteArray;
    QByteArray lPositionByteArray;

    // Serializing
    lMeteoByteArray = serializeMeteoData(mMeteoData);
    lPositionByteArray = serializePositionData(mPositionData);

    // Sending
    sendData(lMeteoByteArray);
    sendData(lPositionByteArray);
}

数据接收器

// Con/Destructors
DataReceiver::DataReceiver(QObject *parent) :
    QObject(parent),
    mTcpServer(new QTcpServer(this)),
    mSourceAddress("127.0.0.1"),
    mSourcePort(51470)
{
    initData();

    connect(mTcpServer, SIGNAL(newConnection()),    this, SLOT(onNewConnection()));

    if(!mTcpServer->listen(QHostAddress(getSourceAddress()), getSourcePort()))
        qDebug() << "<DataReceiver> Server could not start. ";
    else
        qDebug() << "<DataReceiver> Server started !";
}

DataReceiver::DataReceiver(const QString &pSourceAddress,
                      const unsigned int &pSourcePort,
                      QObject *parent) :
    QObject(parent),
    mTcpServer(new QTcpServer(this)),
    mSourceAddress(pSourceAddress),
    mSourcePort(pSourcePort)
{
    initData();

    connect(mTcpServer, SIGNAL(newConnection()),    this, SLOT(onNewConnection()));

    if(!mTcpServer->listen(QHostAddress(getSourceAddress()), getSourcePort()))
        qDebug() << "<DataReceiver> Server could not start. ";
    else
        qDebug() << "<DataReceiver> Server started !";

}

DataReceiver::~DataReceiver(){
    if(mTcpSocket != nullptr) delete mTcpSocket;
    delete mTcpServer;

    if(mTcpSocket != nullptr)
        delete mTcpSocket;
}

// Getters
QTcpServer *DataReceiver::getTcpServer(void) const{
    return mTcpServer;
}

QString DataReceiver::getSourceAddress(void) const{
    return mSourceAddress;
}

unsigned int DataReceiver::getSourcePort(void) const{
    return mSourcePort;
}

positionData_t DataReceiver::getPositionData(void) const{
    return mPositionData;
}

meteoData_t DataReceiver::getMeteoData(void) const{
    return mMeteoData;
}

// Setters
void DataReceiver::setSourceAddress(const QString &pSourceAddress){
    mSourceAddress = pSourceAddress;
}

void DataReceiver::setSourcePort(const unsigned int &pSourcePort){
    mSourcePort = pSourcePort;
}

void DataReceiver::setPositionData(const positionData_t &pPositionData){
    mPositionData = pPositionData;
}

void DataReceiver::setMeteoData(const meteoData_t &pMeteoData){
    mMeteoData = pMeteoData;
}

// Data Management
void DataReceiver::initPositionData(void){
    mPositionData.messageID = METEO_MESSAGE;
    mPositionData.pitch = .0;
    mPositionData.roll = .0;
    mPositionData.yaw = .0;
    mPositionData.a_x = .0;
    mPositionData.a_y = .0;
    mPositionData.a_z = .0;
}

void DataReceiver::initMeteoData(void){
    mMeteoData.messageID = POSITION_MESSAGE;
    mMeteoData.temperature = .0;
    mMeteoData.humidity = .0;
    mMeteoData.pressure = .0;
}

void DataReceiver::initData(void){
    initPositionData();
    initMeteoData();
}

void DataReceiver::reinitData(void){
    initData();
}

// Public Slots
void DataReceiver::onConnect(){
    qDebug() << "QTcpSocket connected...";
}

void DataReceiver::onDisconnect(){
    qDebug() << "QTcpSocket disconnected...";
    disconnect(mTcpSocket, SIGNAL(readyRead()), this, SLOT(onDataReceived()));
    disconnect(mTcpSocket, SIGNAL(disconnected()), this, SLOT(onDisconnect()));
}

void DataReceiver::onBytesWritten(qint64 bytes){
    qDebug() << bytes << " bytes written to QTcpSocket...";
}

void DataReceiver::onDataReceived(){
    // Not yet implemented, code is for testing
    qDebug() << "onDataReceived called !";

    QByteArray lReceivedData;

    while(mTcpSocket->bytesAvailable()){
        lReceivedData = mTcpSocket->read(mTcpSocket->bytesAvailable());
        decodeData(lReceivedData);
        qDebug() << lReceivedData << "\n";
    }
}

void DataReceiver::onNewConnection(){
    qDebug() << "onNewConnection called !";
    mTcpSocket = mTcpServer->nextPendingConnection();
    mTcpSocket->setSocketOption(QAbstractSocket::ReadOnly, true);

    connect(mTcpSocket, SIGNAL(readyRead()),    this, SLOT(onDataReceived()));
    connect(mTcpSocket, SIGNAL(disconnected()), this, SLOT(onDisconnect()));
}

void DataReceiver::onDataChanged(void){
    qDebug() << "onDataChanged called !";
    qDebug() << "\nPrinting mMeteoData : ";
    qDebug() << "mMeteoData.messageID" << mMeteoData.messageID;
    qDebug() << "mMeteoData.temperature" << mMeteoData.temperature;
    qDebug() << "mMeteoData.humidity" << mMeteoData.humidity;
    qDebug() << "mMeteoData.pressure" << mMeteoData.pressure;
    qDebug() << "\nPrinting mPositionData";
    qDebug() << "mPositionData.messageID" << mPositionData.messageID;
    qDebug() << "mPositionData.north" << mPositionData.north;
    qDebug() << "mPositionData.pitch" << mPositionData.pitch;
    qDebug() << "mPositionData.roll" << mPositionData.roll;
    qDebug() << "mPositionData.yaw" << mPositionData.yaw;
    qDebug() << "mPositionData.a_x" << mPositionData.a_x;
    qDebug() << "mPositionData.a_y" << mPositionData.a_y;
    qDebug() << "mPositionData.a_z" << mPositionData.a_z;
}

// Private Methods
void DataReceiver::decodeData(const QByteArray &pMessage){
    // Not yet implemented

    quint8 tempMessageID = fetchMessageID(pMessage);

    switch(tempMessageID){
        case UNKNOWN_MESSAGE:
            break;
        case METEO_MESSAGE:
            mMeteoData = deserializeMeteoData(pMessage);
            emit dataChanged();
            break;
        case POSITION_MESSAGE:
            mPositionData = deserializePositionData(pMessage);
            emit dataChanged();
            break;
    }

    return;
}

更多信息

  • 我发送两种类型的数据,均来自结构。 在接收方,我对数据进行解码,识别并设置相应的属性。
  • 接收器类在QT GUI应用程序中使用。 它不是特别线程化的。 我真的不知道是否有必要,因为在开始时会按计划定期接收数据。

结论

我真的很想找到一个解决方案...我尝试了一些无济于事的事情,例如更改了我读取套接字的方式或使用了QTcpSocket::flush()方法(不确定它是否按照我的想法去做)

非常感谢Clovel

奖金

我还希望能够打开de Receiver端并让发送方自动检测到它,然后开始将数据发送到Receiver。 我需要对此进行更多的研究,但是如果您有个建议,不客气!

虽然@Kuba Ober注释似乎可以解决发送方的锁定问题,但我也会提供有关TCP的建议,因为一个发送操作可能会导致多个readyRead SIGNAL,并且多个发送操作可能会导致单个readyRead SIGNAL,所以我的建议是编写一个小的协议以避免数据损坏的问题!

在这里写了一个协议,它已经被广泛接受,现在我正在改进它!

以下示例是通用示例,因此您必须对其进行调整以适合您的需求,但是我认为您可以轻松完成此操作:),已经在Windows 10中使用Qt 5.5.1 MinGW进行了测试。

为了达到您的目的,我使用UDP套接字发送广播消息,并尝试在范围内找到对等方。

您可以在此处查看完整的项目!

common.h:

#ifndef COMMON_H
#define COMMON_H

#include <QtCore>
#include <QtNetwork>

//Helper macro to set a QObject pointer to nullptr when it's get destroyed
#define SETTONULLPTR(obj) QObject::connect(obj, &QObject::destroyed, [=]{obj = nullptr;})

//Define a max size for each send data operation
#define MAX_NETWORK_CHUNK_SIZE 10*1024*1024

//Create differents types for incomming data, valid for both client and server
namespace Type
{
enum
{
    DataType1,
    DataType2
};
}

//Convert some data of type T to QByteArray, by default in big endian order
template <typename T>
static inline QByteArray getBytes(T input)
{
    QByteArray tmp;
    QDataStream data(&tmp, QIODevice::WriteOnly);
    data << input;
    return tmp;
}

//Convert some QByteArray to data of type T
template <typename T>
static inline T getValue(QByteArray bytes)
{
    T tmp;
    QDataStream data(&bytes, QIODevice::ReadOnly);
    data >> tmp;
    return tmp;
}

//Struct that holds data and information about the peer
typedef struct PeerData {
    QByteArray data;
    QHostAddress host;
    qintptr descriptor;
} PeerData;

#endif // COMMON_H

client.h:

#ifndef CLIENT_H
#define CLIENT_H

#include <QtCore>
#include <QtNetwork>
#include "common.h"

class Client : public QObject
{
    Q_OBJECT
public:
    explicit Client(QObject *parent = nullptr);
    ~Client();

signals:
    void peerFound(QHostAddress);
    void searchPeersFinished();
    void connected(PeerData);
    void disconnected(PeerData);
    void readyRead(PeerData);
    void error(QString);

public slots:
    void abort();
    void connectToHost(const QString &host, quint16 port);
    void searchPeers(quint16 port);
    void stop();
    int write(const QByteArray &data);

private slots:
    void UDPReadyRead();
    void UDPWrite();
    void searchPeersEnd();
    void timeout();
    void connectedPrivate();
    void disconnectedPrivate();
    void errorPrivate(QAbstractSocket::SocketError e);
    void readyReadPrivate();

private:
    QTcpSocket *m_socket;
    QUdpSocket *m_udp_socket;
    quint16 m_udp_port;
    QByteArray m_buffer;
    qint32 m_size;
    QTimer *m_timer;
};

#endif // CLIENT_H

client.cpp:

#include "client.h"

Client::Client(QObject *parent) : QObject(parent)
{
    qRegisterMetaType<PeerData>("PeerData");
    qRegisterMetaType<QHostAddress>("QHostAddress");

    m_socket = nullptr;
    m_size = 0;

    m_udp_socket = nullptr;

    m_timer = new QTimer(this);
    connect(m_timer, &QTimer::timeout, this, &Client::timeout);
    m_timer->setSingleShot(true);
}

Client::~Client()
{
    disconnectedPrivate();
}

//Disconnects the socket
void Client::abort()
{
    if (m_socket)
        m_socket->abort();
}

//Start connection to server
void Client::connectToHost(const QString &host, quint16 port)
{
    if (m_socket)
        return;

    m_socket = new QTcpSocket(this);

    SETTONULLPTR(m_socket);

    connect(m_socket, &QTcpSocket::readyRead, this, &Client::readyReadPrivate);
    connect(m_socket, &QTcpSocket::connected, this, &Client::connectedPrivate);
    connect(m_socket, &QTcpSocket::disconnected, this, &Client::disconnectedPrivate);
    connect(m_socket, static_cast<void(QTcpSocket::*)(QTcpSocket::SocketError)>(&QTcpSocket::error), this, &Client::errorPrivate);

    m_timer->start(10 * 1000);

    m_socket->connectToHost(host, port);
}

//Perform udp broadcast to search peers
void Client::searchPeers(quint16 port)
{
    if (m_udp_socket)
        return;

    m_udp_socket = new QUdpSocket(this);

    SETTONULLPTR(m_udp_socket);

    connect(m_udp_socket, &QUdpSocket::readyRead, this, &Client::UDPReadyRead);

    m_udp_port = port;

    QTimer::singleShot(50, this, &Client::UDPWrite);
}

//Ready read specific for udp socket
void Client::UDPReadyRead()
{
    while (m_udp_socket->hasPendingDatagrams())
    {
        QByteArray data;
        data.resize(m_udp_socket->pendingDatagramSize());

        QHostAddress peer_address;
        quint16 peer_port;

        m_udp_socket->readDatagram(data.data(), data.size(), &peer_address, &peer_port);

        //Test the header used in this udp broadcast, you can freely change this value,
        //but do for both client and server
        if (QLatin1String(data) == QLatin1Literal("TEST"))
            emit peerFound(peer_address);
    }
}

//Send the udp broadcast message to all the network interfaces
void Client::UDPWrite()
{
    QList<QHostAddress> broadcast;

    foreach (QHostAddress address, QNetworkInterface::allAddresses())
    {
        if (address.protocol() == QAbstractSocket::IPv4Protocol)
        {
            address.setAddress(address.toIPv4Address());
            QStringList list = address.toString().split(".");
            list.replace(3, "255");

            QString currentbroadcast = list.join(".");

            QHostAddress address = QHostAddress(QHostAddress(currentbroadcast).toIPv4Address());

            broadcast.append(address);
        }
    }

    QByteArray datagram = QString("TEST").toLatin1();

    foreach (const QHostAddress &address, broadcast)
        m_udp_socket->writeDatagram(datagram, address, m_udp_port);

    //Wait 0.5 seconds for an answer
    QTimer::singleShot(500, this, &Client::searchPeersEnd);
}

//Stop the udp socket
void Client::searchPeersEnd()
{
    m_udp_socket->deleteLater();
    emit searchPeersFinished();
}

void Client::timeout()
{
    emit error("Operation timed out");
    stop();
}

//Handle connected state
void Client::connectedPrivate()
{
    QHostAddress host = m_socket->peerAddress();
    qintptr descriptor = m_socket->socketDescriptor();

    PeerData pd;
    pd.host = host;
    pd.descriptor = descriptor;

    emit connected(pd);

    m_timer->stop();
}

//Handle disconnected state
void Client::disconnectedPrivate()
{
    if (!m_socket)
        return;

    QHostAddress host = m_socket->peerAddress();
    qintptr descriptor = m_socket->socketDescriptor();

    stop();

    PeerData pd;
    pd.host = host;
    pd.descriptor = descriptor;

    emit disconnected(pd);
}

//Handle error
void Client::errorPrivate(QAbstractSocket::SocketError e)
{
    if (e != QAbstractSocket::RemoteHostClosedError)
    {
        QString err = m_socket->errorString();
        emit error(err);
    }

    stop();
}

//Stop the tcp socket
void Client::stop()
{
    m_timer->stop();

    m_size = 0;
    m_buffer.clear();

    if (m_socket)
    {
        m_socket->abort();
        m_socket->deleteLater();
    }
}

//Write data to the server
int Client::write(const QByteArray &data)
{
    if (!m_socket)
        return 0;

    m_socket->write(getBytes<qint32>(data.size()));
    m_socket->write(data);

    return 1;
}

//Receive message from server
void Client::readyReadPrivate()
{
    if (!m_socket)
        return;

    while (m_socket->bytesAvailable() > 0)
    {
        m_buffer.append(m_socket->readAll());

        while ((m_size == 0 && m_buffer.size() >= 4) || (m_size > 0 && m_buffer.size() >= m_size))
        {
            if (m_size == 0 && m_buffer.size() >= 4)
            {
                m_size = getValue<qint32>(m_buffer.mid(0, 4));
                m_buffer.remove(0, 4);

                if (m_size < 0 || m_size > MAX_NETWORK_CHUNK_SIZE)
                {
                    m_socket->abort();
                    return;
                }
            }
            if (m_size > 0 && m_buffer.size() >= m_size)
            {
                QByteArray data = m_buffer.mid(0, m_size);
                m_buffer.remove(0, m_size);
                m_size = 0;

                QHostAddress host = m_socket->peerAddress();
                qintptr descriptor = m_socket->socketDescriptor();

                PeerData pd;
                pd.data = data;
                pd.host = host;
                pd.descriptor = descriptor;

                emit readyRead(pd);
            }
        }
    }
}

server.h:

#ifndef SERVER_H
#define SERVER_H

#include <QtCore>
#include <QtNetwork>
#include "common.h"

class Server : public QObject
{
    Q_OBJECT
public:
    explicit Server(QObject *parent = nullptr);
    ~Server();

signals:
    void connected(PeerData);
    void disconnected(PeerData);
    void listening(quint16);
    void readyRead(PeerData);
    void error(QString);

public slots:
    void abort(qintptr descriptor);
    void listen(quint16 port);
    void stop();
    void writeToHost(const QByteArray &data, qintptr descriptor);
    int writeToAll(const QByteArray &data);

private slots:
    void newConnectionPrivate();
    void UDPListen(quint16 port);
    void UDPReadyRead();
    void readyReadPrivate();
    void disconnectedPrivate();
    void removeSocket(QTcpSocket *socket);

private:
    QTcpServer *m_server;
    QUdpSocket *m_udp_server;

    QList<QTcpSocket*> m_socket_list;
    QHash<qintptr, QTcpSocket*> m_socket_hash;
    QHash<QTcpSocket*, qintptr> m_descriptor_hash;
    QHash<QTcpSocket*, QByteArray> m_buffer_hash;
    QHash<QTcpSocket*, qint32> m_size_hash;
};

#endif // SERVER_H

server.cpp:

#include "server.h"

Server::Server(QObject *parent) : QObject(parent)
{
    qRegisterMetaType<PeerData>("PeerData");
    qRegisterMetaType<QHostAddress>("QHostAddress");

    m_server = nullptr;
    m_udp_server = nullptr;
}

Server::~Server()
{
    stop();
}

//Disconnect the socket specified by descriptor
void Server::abort(qintptr descriptor)
{
    QTcpSocket *socket = m_socket_hash.value(descriptor);
    socket->abort();
}

//Try to start in listening state
void Server::listen(quint16 port)
{
    if (m_server)
        return;

    m_server = new QTcpServer(this);

    SETTONULLPTR(m_server);

    connect(m_server, &QTcpServer::newConnection, this, &Server::newConnectionPrivate);

    if (port < 1)
    {
        emit error("Invalid port value");
        stop();
        return;
    }

    bool is_listening = m_server->listen(QHostAddress::AnyIPv4, port);

    if (!is_listening)
    {
        emit error(m_server->errorString());
        stop();
        return;
    }

    UDPListen(port);

    emit listening(m_server->serverPort());
}

//Start the udp server, used to perform netowork search
void Server::UDPListen(quint16 port)
{
    if (m_udp_server)
        return;

    m_udp_server = new QUdpSocket(this);

    SETTONULLPTR(m_udp_server);

    connect(m_udp_server, &QUdpSocket::readyRead, this, &Server::UDPReadyRead);

    m_udp_server->bind(port);
}

//ReadyRead specific for udp
void Server::UDPReadyRead()
{
    while (m_udp_server->hasPendingDatagrams())
    {
        QByteArray data;
        QHostAddress address;
        quint16 port;

        data.resize(m_udp_server->pendingDatagramSize());
        m_udp_server->readDatagram(data.data(), data.size(), &address, &port);

        //Test the header used in this udp broadcast, you can freely change this value,
        //but do for both client and server
        if (QLatin1String(data) == QLatin1Literal("TEST"))
        {
            m_udp_server->writeDatagram(data, address, port);
        }
    }
}

//Stop both tcp and udp servers and also
//removes peers that may be connected
void Server::stop()
{
    while (!m_socket_list.isEmpty())
        removeSocket(m_socket_list.first());

    if (m_server)
    {
        m_server->close();
        m_server->deleteLater();
    }

    if (m_udp_server)
    {
        m_udp_server->deleteLater();
    }
}

//Handle new connection
void Server::newConnectionPrivate()
{
    while (m_server->hasPendingConnections())
    {
        QTcpSocket *socket = m_server->nextPendingConnection();

        QHostAddress host = socket->peerAddress();
        qintptr descriptor = socket->socketDescriptor();

        QByteArray m_buffer;
        qint32 size = 0;

        m_descriptor_hash.insert(socket, descriptor);
        m_socket_hash.insert(descriptor, socket);
        m_buffer_hash.insert(socket, m_buffer);
        m_size_hash.insert(socket, size);
        m_socket_list.append(socket);

        connect(socket, &QTcpSocket::disconnected, this, &Server::disconnectedPrivate);
        connect(socket, &QTcpSocket::readyRead, this, &Server::readyReadPrivate);

        PeerData pd;
        pd.host = host;
        pd.descriptor = descriptor;

        emit connected(pd);
    }
}

//Write to specific socket if more than one is connected
void Server::writeToHost(const QByteArray &data, qintptr descriptor)
{
    if (!m_socket_hash.contains(descriptor))
        return;

    QTcpSocket *socket = m_socket_hash.value(descriptor);

    socket->write(getBytes<qint32>(data.size()));
    socket->write(data);
}

//Write to all sockets
int Server::writeToAll(const QByteArray &data)
{
    foreach (QTcpSocket *socket, m_socket_list)
    {
        socket->write(getBytes<qint32>(data.size()));
        socket->write(data);
    }

    return m_socket_list.size();
}

//ReadyRead function shared by all sockets connected
void Server::readyReadPrivate()
{
    QTcpSocket *socket = static_cast<QTcpSocket*>(sender());

    QByteArray *m_buffer = &m_buffer_hash[socket];
    qint32 *size = &m_size_hash[socket];
    Q_UNUSED(size)
#define m_size *size
    while (socket->bytesAvailable() > 0)
    {
        m_buffer->append(socket->readAll());

        while ((m_size == 0 && m_buffer->size() >= 4) || (m_size > 0 && m_buffer->size() >= m_size))
        {
            if (m_size == 0 && m_buffer->size() >= 4)
            {
                m_size = getValue<qint32>(m_buffer->mid(0, 4));
                m_buffer->remove(0, 4);

                if (m_size < 0 || m_size > MAX_NETWORK_CHUNK_SIZE)
                {
                    socket->abort();
                    return;
                }
            }
            if (m_size > 0 && m_buffer->size() >= m_size)
            {
                QByteArray data = m_buffer->mid(0, m_size);
                m_buffer->remove(0, m_size);
                m_size = 0;

                QHostAddress host = socket->peerAddress();
                qintptr descriptor = socket->socketDescriptor();

                PeerData pd;
                pd.data = data;
                pd.host = host;
                pd.descriptor = descriptor;

                emit readyRead(pd);
            }
        }
    }
}

//Handle socket disconnection
void Server::disconnectedPrivate()
{
    QTcpSocket *socket = static_cast<QTcpSocket*>(sender());

    QHostAddress host = socket->peerAddress();
    qintptr descriptor = m_descriptor_hash.value(socket);

    removeSocket(socket);

    PeerData pd;
    pd.host = host;
    pd.descriptor = descriptor;

    emit disconnected(pd);
}

//Handle socket removal
void Server::removeSocket(QTcpSocket *socket)
{
    qintptr descriptor = m_descriptor_hash.value(socket);

    m_socket_hash.remove(descriptor);
    m_descriptor_hash.remove(socket);
    m_buffer_hash.remove(socket);
    m_size_hash.remove(socket);

    m_socket_list.removeAll(socket);

    socket->abort();
    socket->deleteLater();
}

客户/worker.h

#ifndef WORKER_H
#define WORKER_H

#include <QtCore>
#include "client.h"

class Worker : public QObject
{
    Q_OBJECT
public:
    explicit Worker(QObject *parent = nullptr);

public slots:
    void start(quint16 port);

private:
    Client m_client;
    quint16 m_port;
    QTimer m_timer;
    double m_double_1;
    double m_double_2;
    QMetaObject::Connection m_connection;
};

#endif // WORKER_H

客户/worker.cpp

#include "worker.h"

Worker::Worker(QObject *parent) : QObject(parent)
{
    m_port = 0;

    m_double_1 = 0;
    m_double_2 = 0;

    m_timer.setInterval(1000);
}

void Worker::start(quint16 port)
{
    m_port = port;

    connect(&m_client, &Client::searchPeersFinished, []{
        qDebug() << "Search peers finished!";
    });

    m_connection = connect(&m_client, &Client::peerFound, [&](const QHostAddress &peer_address){
        disconnect(m_connection); //Disconnect signal, only first peer found will be handled!
        m_client.connectToHost(QHostAddress(peer_address.toIPv4Address()).toString(), m_port);
    });

    connect(&m_client, &Client::error, [](const QString &error){
        qDebug() << "Error:" << qPrintable(error);
    });

    connect(&m_client, &Client::connected, [&](const PeerData &pd){
        qDebug() << "Connected to:" << qPrintable(pd.host.toString());
        m_timer.start();
    });

    connect(&m_client, &Client::disconnected, [](const PeerData &pd){
        qDebug() << "Disconnected from:" << qPrintable(pd.host.toString());
    });

    connect(&m_client, &Client::readyRead, [](const PeerData &pd){
        qDebug() << "Data from" << qPrintable(pd.host.toString())
                 << qPrintable(QString::asprintf("%.2f", getValue<double>(pd.data)));
    });

    connect(&m_timer, &QTimer::timeout, [&]{
        m_double_1 += 0.5; //Just an example of data

        QByteArray data1;
        data1.append(getBytes<quint8>(Type::DataType1)); //Data 1 has Type 1, added as header
        data1.append(getBytes<double>(m_double_1)); //The data itself

        m_client.write(data1); //Write the data1 to the server

        m_double_2 += 1.0; //Just an example of data

        QByteArray data2;
        data2.append(getBytes<quint8>(Type::DataType2)); //Data 2 has Type 2, added as header
        data2.append(getBytes<double>(m_double_2)); //The data itself

        m_client.write(data2); //Write the data2 to the server
    });

    qDebug() << "Searching...";

    m_client.searchPeers(m_port); //Search for peers in range, if found, handle the first and connect to it!
}

客户端/main.cpp

#include <QtCore>
#include "worker.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Worker worker;
    worker.start(1024);

    return a.exec();
}

服务器/worker.h

#ifndef WORKER_H
#define WORKER_H

#include <QtCore>
#include "server.h"

class Worker : public QObject
{
    Q_OBJECT
public:
    explicit Worker(QObject *parent = nullptr);

public slots:
    void start(quint16 port);

private:
    Server m_server;
    quint16 m_port;
};

#endif // WORKER_H

服务器/worker.cpp

#include "worker.h"

Worker::Worker(QObject *parent) : QObject(parent)
{
    m_port = 0;
}

void Worker::start(quint16 port)
{
    m_port = port;

    connect(&m_server, &Server::error, [](const QString &error){
        if (!error.isEmpty())
            qDebug() << "Error:" << qPrintable(error);
    });

    connect(&m_server, &Server::listening, [](quint16 port){
        qDebug() << "Listening on port:" << port;
    });

    connect(&m_server, &Server::connected, [](const PeerData &pd){
        qDebug() << "Connected to:" << qPrintable(pd.host.toString());
    });

    connect(&m_server, &Server::disconnected, [](const PeerData &pd){
        qDebug() << "Disconnected from:" << qPrintable(pd.host.toString());
    });

    connect(&m_server, &Server::readyRead, [&](const PeerData &pd){
        QByteArray data = pd.data;

        if (data.isEmpty())
            return;

        quint8 header = getValue<quint8>(data.mid(0, 1)); //Read the 1 byte header
        data.remove(0, 1); //Remove the header from data

        switch (header)
        {
        case Type::DataType1:
        {
            qDebug() << "Data from" << qPrintable(pd.host.toString())
                     << "DataType1" << qPrintable(QString::asprintf("%.2f", getValue<double>(data)));
            break;
        }
        case Type::DataType2:
        {
            qDebug() << "Data from" << qPrintable(pd.host.toString())
                     << "DataType2" << qPrintable(QString::asprintf("%.2f", getValue<double>(data)));
            break;
        }
        default:
            break;
        }

        m_server.writeToHost(data, pd.descriptor);
    });

    m_server.listen(m_port);
}

服务器/main.cpp

#include <QtCore>
#include "worker.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Worker worker;
    worker.start(1024);

    return a.exec();
}
①如果本文未解决您的问题,请点击查看与本文相关的问题
②如果本文未解决您的问题,请向程序员专用AI小助手提问
暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM