Russian Qt Forum

Qt => Работа с сетью => Тема начата: AntonUfo от Октября 24, 2011, 16:21



Название: Как отсылать клиенту пакеты строго 64 к ?
Отправлено: AntonUfo от Октября 24, 2011, 16:21
Столкнулся с тем что при отсылке сервером клиенту сообщения больше 64к, сообщения не приходят, подскажите плз, как переделать данный кусок кода что бы клиенту высылались данные пакетами 64К ?

Код:
void EchoThread::recievmessages( const QString &strmessage, const QString &arg ){
    QByteArray block2;
    QDataStream out(&block2, QIODevice::WriteOnly);
  
    out.setVersion(QDataStream::Qt_4_4);
    out << (quint16)0; // конец блока

    out << arg;            //куда отправляем сообщение
    out << strmessage; //строка сообщения

    out.device()->seek(0); //подсчет колличества байтов в сформированном пакете и отсылка информации
    quint16 byte = (block2.size() - sizeof(quint16));
    out << byte; //подсчитаем реальный размер блока в байтах

    emit writeToSocket(block2);
}

Зарание спасибо !!!!


UPD: В сокет пишу так:

//для отправки данных сокетом клиенту
connect(this, SIGNAL(writeToSocket(QByteArray)), m_client, SLOT(onWrite(QByteArray)) );


//непосредственно отправляем данные сокетом
void TcpSocket::onWrite(QByteArray block2){
   this->write(block2);
}


Проблема в том что к примеру строка "Тестовая строка" передается нормально, а  строка из 1000 символов нет !


Название: Re: Как отсылать клиенту пакеты строго 64 к ?
Отправлено: Пантер от Октября 24, 2011, 16:30
Покажи как в сокет пишешь.


Название: Re: Как отсылать клиенту пакеты строго 64 к ?
Отправлено: LisandreL от Октября 24, 2011, 21:14
Столкнулся с тем что при отсылке сервером клиенту сообщения больше 64к
...
а строка из 1000 символов нет!
1000 символов - это (в зависмости от кодировки) 1000~4000 байт, что явно меньше 64к.
А так можете попробовать после write вызывать waitForBytesWritten( -1 ).


Название: Re: Как отсылать клиенту пакеты строго 64 к ?
Отправлено: AntonUfo от Октября 25, 2011, 08:12
Столкнулся с тем что при отсылке сервером клиенту сообщения больше 64к
...
а строка из 1000 символов нет!
1000 символов - это (в зависмости от кодировки) 1000~4000 байт, что явно меньше 64к.
А так можете попробовать после write вызывать waitForBytesWritten( -1 ).

все равно ничего не получается ! я уже просто не знаю куда копать....


Название: Re: Как отсылать клиенту пакеты строго 64 к ?
Отправлено: LisandreL от Октября 25, 2011, 08:33
Стоп:
Код:
quint16 byte = (block2.size() - sizeof(quint16));
quint16 какой диапазон имеет? 0~65535
То есть при длине сообщения более 64к вы заполняете поле длины неверными данными.

Если сервер ваш, то покажите и код чтения. Может и там косяки есть.


Название: Re: Как отсылать клиенту пакеты строго 64 к ?
Отправлено: AntonUfo от Октября 25, 2011, 08:44
Стоп:
Код:
quint16 byte = (block2.size() - sizeof(quint16));
quint16 какой диапазон имеет? 0~65535
То есть при длине сообщения более 64к вы заполняете поле длины неверными данными.

Если сервер ваш, то покажите и код чтения. Может и там косяки есть.



Вот код код клиента который получает сообщения:

Код:
//Получаем данные от сервера, и вывожу полученную информацию в нужные места в клиенте
void ClientRam::updateTcpWidget()
{
QString arg;
QString strmessage;

    QDataStream in(&tcpSocket);
    in.setVersion(QDataStream::Qt_4_4);

viewResultAction->setEnabled(true);
forever {

        if (nextBlockSize == 0) {
            if (tcpSocket.bytesAvailable() < sizeof(quint16))
                break;
            in >> nextBlockSize;
        }

        if (nextBlockSize == 0xFFFF) {
connectUp = false;
            closeConnection();
            break;
        }

        if (tcpSocket.bytesAvailable() < nextBlockSize)
            break;

in >> arg;
in >> strmessage;

//вывод информации в поле вывода
if (arg == tr( "вывод" )){
emit recievmessages(strmessage); //вывожу информацию в поле вывода....
}
//вывод информации в статусбар
if (arg == tr( "статус" )){
statusBar()->showMessage(strmessage );//вывожу информацию в статус бар....
}

nextBlockSize = 0; //готовы получить новую порцию данных
}//конец forever
}


Название: Re: Как отсылать клиенту пакеты строго 64 к ?
Отправлено: Янковский Александр от Октября 25, 2011, 10:54
По UDP более 64 кБ не отправишь за один раз.
Каждая датаграмма (если не ошибаюсь 512 байт) клеится операционной системой как раз до размера 64 кБ.

Выход конечно же есть. Но нужно уже строить что-то более высокое, чем просто запихнуть данные в сокет.
А именно завести 2 счетчика:
  1) номер массива (сквозной);
  2) номер блока данных внутри массива (от 0 до N)

Ну и соответственно паковать данные. В начале идет структура с указанными выше значениями счетчиков + фактический размер данных, запиханных в эту пачку (64 кБ максимум).

Ну и потом естественно сами данные, но не более чем весь возможный массив.

Удачи!


Название: Re: Как отсылать клиенту пакеты строго 64 к ?
Отправлено: LisandreL от Октября 25, 2011, 11:53
По UDP более 64 кБ не отправишь за один раз.
tcpSocket. При чём тут UDP?

Код:
if (nextBlockSize == 0xFFFF)
Что за «магическая константа», если вы предполагаете, что у вас длина блока может быть более 64к (а значит и ровно 0xFFFF)?

Код:
if (tcpSocket.bytesAvailable() < nextBlockSize)
            break;
С чего вы решили, что тут надо выходить? Ну недошли ещё все данные, надо ж подождать (continue) а не выходить (break).

Про идентификацию пакетов русскими словами я вообще промолчу.

Код
C++ (Qt)
void ClientRam::updateTcpWidget()
{
QString arg;
QString strmessage;
 
   QDataStream in(&tcpSocket);
   in.setVersion(QDataStream::Qt_4_4);
 
viewResultAction->setEnabled(true);
while ( tcpSocket.state() == QAbstractSocket::ConnectedState ) {
 
       if (nextBlockSize == 0) {
           if (tcpSocket.bytesAvailable() < sizeof(quint16))
               continue;
           in >> nextBlockSize;
       }
 
       if (tcpSocket.bytesAvailable() < nextBlockSize)
           continue;
 
in >> arg;
in >> strmessage;
 
//вывод информации в поле вывода
if (arg == tr( "вывод" )){
emit recievmessages(strmessage); //вывожу информацию в поле вывода....
}
                      else
//вывод информации в статусбар
if (arg == tr( "статус" )){
statusBar()->showMessage(strmessage );//вывожу информацию в статус бар....
}
else
                     {
statusBar()->showMessage( "НЁХ: " + arg + ": "+ strmessage );//вывожу информацию в статус бар....
                     }
nextBlockSize = 0; //готовы получить новую порцию данных
 
}//конец forever
}

Если нужны пакеты длиннее 65535 байт менятьтип поля размера в заголовке с quint16 на quint32 или quint64.


Название: Re: Как отсылать клиенту пакеты строго 64 к ?
Отправлено: RedDog от Октября 25, 2011, 12:52
К стати, по поводу QDataStream через сокеты. Как то пытался отправлять файлы пакетами по 64к через него, и почему то к каждому пакету примешивалось 4 байта хз откуда.
Через write(...) все прекрано работает.


Название: Re: Как отсылать клиенту пакеты строго 64 к ?
Отправлено: ddrtn от Октября 25, 2011, 13:21
К стати, по поводу QDataStream через сокеты. Как то пытался отправлять файлы пакетами по 64к через него, и почему то к каждому пакету примешивалось 4 байта хз откуда.
Через write(...) все прекрано работает.

В начале посылки добавлялся ее размер. Смотри про правила сериализации через QDataStream


Название: Re: Как отсылать клиенту пакеты строго 64 к ?
Отправлено: AntonUfo от Октября 26, 2011, 08:48
Про идентификацию пакетов русскими словами я вообще промолчу.
Если нужны пакеты длиннее 65535 байт менять тип поля размера в заголовке с quint16 на quint32 или quint64.

1. спасибо за разъяснения, поменял тип поля размера и все заработало
2. По поводу идентификации пакетов русскими словами, может быть подскажете как правильно ?


Название: Re: Как отсылать клиенту пакеты строго 64 к ?
Отправлено: LisandreL от Октября 26, 2011, 09:58
По поводу идентификации пакетов русскими словами, может быть подскажете как правильно?
Ну классический вариант - числовыми константами.
Ну или хотя бы английскими словами - не будет проблем с кодировками.