LINUX.ORG.RU

QTcpSocket win и странное поведение

 , ,


0

1

Все доброе утро! Столкнулся со следующей проблемой. Есть приложение, работающее на tcp сокетах. Все по классике: Подключение, прием/передача команд. После каждой выданной команды делаю flush. На 95% машин работает без проблем, однако есть машины, на которых каждый запуск приложения ведет себя по разному, поясню. Примерно каждый 3-4 запуск на запрос connect может не прийти никакого ответа -> как следствие, приложение не может подключиться, либо, прилетает конект, но следующая команда почему то дублируется, т.е. я выдаю одну строчку hello а в сеть улетает hellohello (смотрел через wireshark). Из-за таких проблем клиентам приходится запускать приложение на несколько раз... С чем это может быть связано? Работа с сокетом происходит следующим образом:

class TcpSocket : public QTcpSocket
{
    Q_OBJECT

    public:
        explicit TcpSocket(QObject *parent = 0);
        void sendData(QString, QMap<QString, QVariant> &, QString = "rpc", QString id = "", bool = true);
...

    public slots:
        void slotRecvData();

    private:
        void parseHeader(QString &);

    private:
        QString     data;
        int         totalSize;
        Logger      *log;
};

TcpSocket :: TcpSocket(QObject *parent) :
    QTcpSocket(parent),
    log(LogManager::get_logging()->get_logger("Network")) {
    connect(this, SIGNAL(readyRead()), SLOT(slotRecvData()));
    init_error_map();
}

void TcpSocket :: slotRecvData() {
    QString                     buf;
    QMap<QString, QVariant>     map;
    QJsonDocument               doc;

    log -> set_param("SESSION", "Server");

    while(this -> bytesAvailable())
        try {
            buf = this -> readAll();
            if(!data.isEmpty()) {
                data += buf;
            }
            else {
                parseHeader(buf);
            }

            while(true) {
                if(data.size() < totalSize) {
                    break;
                }
                else if(data.size() > totalSize) {
                    doc = QJsonDocument::fromJson(data.left(totalSize).toLocal8Bit().data());
                    log -> debug() << totalSize << "|" << doc.toJson().data() << '\n';
                    map = doc.toVariant().toMap();
                    emit dataReceived(map);
                    data = data.mid(totalSize);
                    parseHeader(data);
                }
                else {
                    doc = QJsonDocument::fromJson(data.toLocal8Bit().data());
                    log -> debug() << totalSize << "|" << doc.toJson().data() << '\n';
                    map = doc.toVariant().toMap();
                    emit dataReceived(map);
                    data.clear();
                    totalSize = 0;
                    break;
                }
            }
        }
        catch (NetworkHeaderException &s) {
            log -> error() << "Error while recv cmd: " << s.what() << '\n';
            log -> error() << "Ошибка данных сети: " << buf.toStdString() << "\n";
            data.clear();
            totalSize = 0;
            setSocketError(QAbstractSocket::ProxyConnectionRefusedError);
            disconnectFromHost();
            break;
        }
}

void TcpSocket :: sendData(QString cmd,
                           QMap<QString, QVariant> &params,
                           QString type,
                           QString id,
                           bool log_cmd) {
    QMap<QString, QVariant>     map;

    map["name"] = cmd;
    map["params"] = params;
    map["id"] = id;
    map["type"] = type;

    log -> set_param("SESSION", "Client");

    try {
        QVariant        jsonVariant(map);
        QString         jsonStr = QJsonDocument::fromVariant(jsonVariant).toJson();

        QByteArray      _data = jsonStr.toUtf8().data();

        _data.prepend("|");
        _data.prepend(QString::number(_data.size() - 1).toStdString().data());
        if(log_cmd) {
            log -> debug() << _data.data();
        }
        write(_data);
        flush();
    }
    catch (exception &e) {
        log -> error() << "Error while send cmd: " << e.what() << '\n';
    }
}

void TcpSocket :: parseHeader(QString &buf) {
    int index = buf.indexOf('|');
    if(index == -1) {
        throw NetworkHeaderException();
    }
    bool    res;
    totalSize = buf.left(index).toInt(&res);
    if(!res) {
        throw NetworkHeaderException();
    }
    data = buf.mid(index + 1);
}

пробовал еще telnet подключаться, всегда подключается...

energyclab
() автор топика
Ответ на: комментарий от grondek
...
// Сокет
    mainSocket = new TcpSocket();
    connect(mainSocket,
            &TcpSocket::connected,
            this,
            &UpdateManager::socketConnected,
            Qt::QueuedConnection);
    connect(mainSocket,
            &TcpSocket::dataReceived,
            this,
            &UpdateManager::dataReceived,
            Qt::QueuedConnection);
    connect(mainSocket,
            &TcpSocket::disconnected,
            this,
            &UpdateManager::socketDisconnected,
            Qt::QueuedConnection);
    connect(mainSocket,
            static_cast<void (TcpSocket::*)(QAbstractSocket::SocketError)>(&TcpSocket::error),
            this,
            &UpdateManager::socketError,
            Qt::QueuedConnection);

    QThread     *workerThread = new QThread();
    mainSocket -> moveToThread(workerThread);
    workerThread -> start();
...

void UpdateManager::connectToHost(QString url) {
    QStringList host_port;

    host_port = url.split(":");
    if(host_port.size() != 2) {
        log -> warning() << "Некорректный адрес сервера\n";
        socketError(QAbstractSocket::UnknownSocketError);
        return;
    }
    log -> info() << "Подключение к " << url.toStdString()
                  << ", попытка № " << current_try + 1<< '\n';
    qApp -> processEvents();
    connect_timer_id = startTimer(CONNECT_TIMEOUT * 1000);
    mainSocket -> connectToHost(host_port[0], host_port[1].toShort());
}

...
void UpdateManager::socketConnected() {
    if(connect_timer_id) {
        killTimer(connect_timer_id);
        connect_timer_id = 0;
    }

    QMap<QString, QVariant>     plaform;

    mainSocket -> write(HELLOCOMAGIC);
    mainSocket -> flush();

...

    mainSocket -> sendData(info_cmd.name, plaform, "rpc", id);
    mainSocket -> flush();
}


Зачем я сделал moveToThread, сейчас вспомнить не могу, но его можно убрать
energyclab
() автор топика
Ответ на: комментарий от x905

Сори, я не закрыл тему... проблема решилась удалением строк

QThread     *workerThread = new QThread();
mainSocket -> moveToThread(workerThread);
workerThread -> start();

Вообще данная проблема наблюдалась только на очень слабом железе...(Seleron и Athlon годов 2000х - 2002х)...Возможно связано с зачатками в этих процессорах технологии виртуализации (hyperthreading, когда второе ядро было эмулировано и работало на 60%). В любом случае спасибо за потраченное время...

energyclab
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.