Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Qt и кроссплатформенное программирование С/С++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 01.05.2011, 18:03   #1
niklep
Новичок
Джуниор
 
Регистрация: 01.05.2011
Сообщений: 2
По умолчанию QTcpServer и прием команд от telnet

Необходимо написать серверное приложение, которое принимало бы команды от другого приложения, после некоторых действий возвращало бы ему ответ.
Сервер написал. Также для теста написал клиента. Оба на 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. И никаких данных сервером не принимается. Что мне сделать для исправления ситуации?
niklep вне форума Ответить с цитированием
Старый 02.05.2011, 11:31   #2
profi
Участник клуба Подтвердите свой е-майл
 
Регистрация: 19.11.2007
Сообщений: 1,022
По умолчанию

Цитата:
А в итоге вышло так, что мой сервер не может принять команды от клиента, написанного на C#
Если честно, то не важно на чем будет написан клиент. Нужно знать какой порядок байтов (от старшего к младшему или от младшего к старшему) используется при обмене сообщениями, например установка порядка байтов в Qt для QDataStream:
Код:
QDataStream in(clientSocket);
in.setByteOrder(QDataStream::LittleEndian);
Это уже посмотрите в снифере.
Советую скачать любой снифер и просто посмотреть как формируются пакеты от сервера к клиенту и от клиента к серверу.
profi вне форума Ответить с цитированием
Старый 02.05.2011, 22:49   #3
niklep
Новичок
Джуниор
 
Регистрация: 01.05.2011
Сообщений: 2
По умолчанию

Решил проблему. Чтоб 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);
}
Здесь вообще просто. Просто пишу в поток, указывая длину данных.
niklep вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Indy Telnet выполнение команд Kigmatig Работа с сетью в Delphi 0 27.03.2011 23:21
telnet c++ Mu$T@nG Помощь студентам 19 12.08.2010 18:55
реализация команд с помощью набора других команд zhenyaa Assembler - Ассемблер (FASM, MASM, WASM, NASM, GoASM, Gas, RosAsm, HLA) и не рекомендуем TASM 5 08.11.2009 21:37
Telnet+smtp MaximeMD Помощь студентам 2 03.09.2009 19:07