Поиск:

Ответ в темуСоздание новой темы Создание опроса
> QTcpServer и прием команд от telnet 
:(
    Опции темы
niklep
Дата 1.5.2011, 15:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 43
Регистрация: 9.5.2010

Репутация: нет
Всего: нет



Необходимо написать серверное приложение, которое принимало бы команды от другого приложения, после некоторых действий возвращало бы ему ответ.
Сервер написал. Также для теста написал клиента. Оба на Qt. Реализации сетевого взаимодействия брал из учебников. А в итоге вышло так, что мой сервер не может принять команды от клиента, написанного на C# (это приложение написано другим человеком, мы с ним в паре работаем). В ходе выяснения причин неработоспособности схемы был сделан следующий вывод: проблема в моем приложении, поскольку приложение партнера способно взаимодействовать с telnet'ом, а мое нет. То есть мое приложение не универсально и работает только для приложения, которое использует QDataStream для передачи данных.
В моем коде потенциально есть "2 слабых звена":
1. Метод отправки данных клиенту.
Код

void ServerSocket::sendToClient(QTcpSocket* pSocket, const QString str)
{
    QByteArray arrBlock;
    QDataStream out(&arrBlock, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_7);
    out << quint16(0);
    out << QTime::currentTime();
    out << str;
        out.device()->seek(0);
    out << quint16(arrBlock.size() - sizeof(quint16));
    pSocket->write(arrBlock);
}

При отправке таким образом данных клиенту в начале строки появлялся мусор (размер массива QDataStream там забит). Метод был переделан:
Код

void ServerSocket::sendToClient(QTcpSocket* pSocket, const QString str)
{
    QByteArray arrBlock;
    QDataStream out(&arrBlock, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_7);
    QByteArray ba_temp = str.toUtf8(); // переводим QString
    char *str2 = ba_temp.data(); // в char
    out.writeRawData(str2, strlen(str2));
    pSocket->write(arrBlock);
}

Теперь отправка данных клиенту происходит нормально (по крайней мере telnet их получает в нужном виде).

2. Метод приема данных от клиента. Здесь у меня ступор.
Код

void ServerSocket::slotReadClient()
{
    clientSocket = (QTcpSocket*)sender();
    QDataStream in(clientSocket);
    in.setVersion(QDataStream::Qt_4_7);
    for (;;)
    {
        if (nextBlockSize==0)
        {
            if (clientSocket->bytesAvailable() < sizeof(quint16))
                return;
            in >> nextBlockSize;
        }
        if (clientSocket->bytesAvailable() < nextBlockSize)
            return;

        QTime time;
        QString str;
        in >> time >> str;
        str += "\r";
        QByteArray ba = str.toUtf8(); // переводим QString
        char *str2 = ba.data(); // в char
        nextBlockSize=0;
        connect(temp_com->port, SIGNAL(readyRead()), this, SLOT(slotReadCom()));
        temp_com->writeToPort(str2);
    }
}

Если сервер взаимодействует с клиентом на Qt, то срабатывает ветка
Код

if (nextBlockSize==0)
{
    if (clientSocket->bytesAvailable() < sizeof(quint16))
        return;
    in >> nextBlockSize;
}

А вот в случае с telnet nextBlockSize всегда равен 65531. И никаких данных сервером не принимается. Что мне сделать для исправления ситуации?
PM MAIL   Вверх
borisbn
Дата 2.5.2011, 13:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 48
Всего: 135



Скажу сразу - прочитал твой код по-диагонали, не вникал, но...
Если требуется поддержать сторонний протокол, то лучше не использовать QDataStream, потому, что он может вставлять в поток версию алгоритма, информацию о типе, размер, да мало ли чего ещё.
У QTcpSocket есть функции для передачи/приёма "сырых" данных
qint64 QIODevice::write ( const QByteArray & byteArray )
QByteArray QIODevice::read ( qint64 maxSize )


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
niklep
Дата 2.5.2011, 21:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 43
Регистрация: 9.5.2010

Репутация: нет
Всего: нет



Решил проблему. Чтоб QDataStream не пихал в начало массива мусор, можно использовать методы:
Код

readRawData
writeRawData

Ниже моя реализация.
Читать данные от клиента:
Код

void ServerSocket::slotReadClient()
{
    clientSocket = (QTcpSocket*)sender();
    QDataStream in(clientSocket);
    in.setVersion(QDataStream::Qt_4_7);
    QString str="";
    QByteArray ba = str.toUtf8(); // переводим QString
    char *str2 = ba.data(); // в char
    int ss = static_cast<int>(clientSocket->bytesAvailable());
    in.readRawData(str2, ss);
    QString str3(str2);
    str3 = str3.mid(0,ss);
    str3 = str3+"\r";
    QByteArray ba2 = str3.toUtf8(); // переводим QString
    char *str4 = ba2.data(); // в char
    connect(temp_com->port, SIGNAL(readyRead()), this, SLOT(slotReadCom()));
    temp_com->writeToPort(str4);
}

Конечно, не оптимально. Лень было даже разбираться почему не работал поиск подстроки в типе string и я сделал лишнюю строку QString. Поиск подстроки я делал потому, что при выполнении
Код

in.readRawData(str2, ss);

по идее в str2 должно было записаться только указанное количество (ss) символов из потока, а писалось много мусора. Поэтому я строку потом обрезал.

Запись данных в клиента:
Код

void ServerSocket::sendToClient(QTcpSocket* pSocket, const QString str)
{
    QByteArray arrBlock;
    QDataStream out(&arrBlock, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_7);
    QByteArray ba_temp = str.toUtf8(); // переводим QString
    char *str2 = ba_temp.data(); // в char
    out.writeRawData(str2, strlen(str2));
    pSocket->write(arrBlock);
}

Здесь вообще просто. Просто пишу в поток, указывая длину данных.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Кроссплатформенное программирование, QT/Gtk+/wxWidgets"
JackYF
Любитель
  • В заголовке темы в квадратных скобках обозначьте используемую вами библиотеку, например: [QT],[GTK],[wx].
  • Если вопрос актуален только для некоторой версии библиотеки, либо, если вы пользуетесь не самой последней версией, укажите это. Например: [QT4], [GTK2].
  • Все начинающие изучать Qt - не забудьте зайти сюда.
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • В вопросе укажите полную версию версию библиотеки, а также все дополнительные используемые программные пакеты.
  • Не забывайте пользоваться кнопкой "Код".
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к тематике этого раздела. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, Любитель.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets | Следующая тема »


 




[ Время генерации скрипта: 0.0413 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.