Russian Qt Forum
Ноябрь 23, 2024, 09:51 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: вопрос по qtcpsocket  (Прочитано 6334 раз)
koldun90
Крякер
****
Offline Offline

Сообщений: 345


Просмотр профиля
« : Февраль 07, 2018, 21:38 »

здравствуйте есть сервер основанный на qtcpserver и клиент на qtcpsocket

сервер посылает сообщение клиенту в цикле ввида
Код
C++ (Qt)
for (in t i=0;i<30;i++)
{
   socket->write(QByteArray::number(i));
 
}


собственно клиент принимает сообщение в слоте связанном с сигналом readyread

прием данных от сервака
Код
C++ (Qt)
void ReceiveServer
{
  cout<<sok->readAll().data<<endl;
}


соответственно в консоль выводится сообщение

Те срабатывает два сигнала ready read
012345678910111213141516

17181920212223242526272829


Но вот в чем вопрос можно ли сделать так чтобы сервер отсылал данные (сделал 1 write) а на клиенте сработал readyread и он получил то что я ему послал за одну итерацию цикла ( в данном примере одно чило из 30)

просто на скока я понимаю write асинхронный он пишет сначало в свой внутренний буфер, а потом когда решит выплевывает клиенту
если делаю так

Код
C++ (Qt)
socket->write(QByteArray::number(i));
socket->flush();
то все тоже самое
Вообщем как-то можно организовать полностью синхронную отправку данных?

« Последнее редактирование: Февраль 07, 2018, 21:41 от koldun90 » Записан
koldun90
Крякер
****
Offline Offline

Сообщений: 345


Просмотр профиля
« Ответ #1 : Февраль 07, 2018, 22:53 »

Код
C++ (Qt)
for (in t i=0;i<30;i++)
{
 
   socket->write(QByteArray::number(i));
   socket->flush();
   usleep(8000)
}
 

В принципе можно сделать задержу 8000 микросекунд =0,008 секунды с помощью usleep
но проблема в больших данных
Пример в данном случае на числах а я буду отсылать содержимое папок
Те допустим в папке /usr/bin содержится много файлов у меня порядка 1700
и мне нужно отослать все файлы в этой папке какие есть клиенту чтобы он у себя их отобразил в QTreeVidget
и каждый write у меня будет имя файла
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #2 : Февраль 08, 2018, 08:06 »

Вообщем как-то можно организовать полностью синхронную отправку данных?

Если поднапрячься можно, путем настройки сокетов, паузами или любыми другими костылями), которые сломаются в самый неподходящий момент. Но вопрос ЗАЧЕМ?
Асинхронный write/read организуют максимально эффективный способ передачи данных. Любая синхронизация - снижение производительности (причем на порядки величин), дополнительные ограничения и т.п.
Пакеты данных могут склеиваться или напротив приходить не полностью, а частями. Их в любом случае нужно обрабатывать по мере прихода данных - отделять друг от друга или склеивать в соответствии с реализуемым протоколом обмена.
Никто не гарантирует, что даже int придет полностью за 1 readyRead(). Поэтому имеется возможность узнать сколько байт пришло с помощью bytesAvailable() и производить считывание только при их достаточном количестве.
Записан
koldun90
Крякер
****
Offline Offline

Сообщений: 345


Просмотр профиля
« Ответ #3 : Февраль 08, 2018, 17:31 »

Я вас понял. Но как мне лучше организовать все это дело.
Смысл в том что я отсылаю команду серверу с параметром имя папки.
Сервер получает данную команду.
Он должен мне переслать имена файлов и папок в заданном каталоге(допустим каталог /usr/bin). Я получаю содержимое там порядка 1700 объектов)
1700 фалов грубо говоря каждый файл имеет длину 5 байт. В итоге мне нужно будет переслать порядка 20000 байт. Я так понял вы предлагаете мне сделать
Один qtcpsocket::write. В котором я сразу пошлю порядка 20000 байт?

Те я с сервака посылаю 20000 байт. А на клинте я тупо жду когда мне все эти байты придут и только потом когда получу все 20000 байт далее уже двигаться по коду...
« Последнее редактирование: Февраль 08, 2018, 17:39 от koldun90 » Записан
koldun90
Крякер
****
Offline Offline

Сообщений: 345


Просмотр профиля
« Ответ #4 : Февраль 09, 2018, 08:36 »

Как в примере qt. Client fortune example.
Я так понял что в начале нужно послать размер затем
Затем ждать чтоб весь пакет поступил в сокет . И только потом его прочитать.
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #5 : Февраль 09, 2018, 08:41 »

Я так понял вы предлагаете мне сделать
Один qtcpsocket::write. В котором я сразу пошлю порядка 20000 байт?

Нет, я не это имел ввиду). Как вам отправлять данные вы сами решите, по одному имени или все сразу.
Вы хотите организовать клиент серверное взаимодействие, которое реализуется посредством какого-то прикладного протокола.
Протокол обмена подразумевает, что данные передаются пакетами, а не непрерывно.
Пакет данных имеет какой-то формат - как минимум количество байт и внутреннее содержимое.
Из сокета вычитываются пакеты данных, а уже потом интерпретируется их содержимое.

На стороне отправителя:
* сериализуем сообщение/команду в пакет (например, QByteArray).
* пакет отправляется в сокет - в виде {размер, содержимое}

На стороне получателя:
* ожидаем, когда в сокете будет достаточно байт для чтения размера пакета
* вычитываем размер пакета
* ожидаем, когда в сокете будет достаточно байт для чтения содержимого пакета
* вычитываем содержимое пакета
* десериализуем сообщение/команду из пакета
* обрабатываем сообщение/команду.


Записан
koldun90
Крякер
****
Offline Offline

Сообщений: 345


Просмотр профиля
« Ответ #6 : Февраль 09, 2018, 09:56 »

Это понятно что структура пакета у меня будет (размер+данные).
Вся проблема в том что если я в цикле посылаю 1500
Пакетов(делаю write) то мне же известен размер одного посылаемого пакета.
Далее я прочитал размер пакета(packsize)
Далее я жду пока поступят данные пакета затем учитывают их по вся проблема в то что пакеты склеиваются друг с другом и как их обрабатывать непонятно
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #7 : Февраль 09, 2018, 10:54 »

Псевдокод

Код
C++ (Qt)
 
class CommandReader
   : public QObject
{
...
   QTcpSocket socket;
   qint32 packet_byte_count;
};
 
void onReadyRead ()
{
   QDataStream stream( &socket );
 
   while ( !stream.atEnd() )
   {
       if ( stream.device()->bytesAvailable() < sizeof( qint32 ) )
           return;
       stream >> packet_byte_count;
       if ( stream.device()->bytesAvailable() < packet_byte_count )
           return;
       packet_byte_count = qint32();
 
       MyCommand command;
       stream >> command;
       processCommand( command );
   }
}
 
 
Записан
koldun90
Крякер
****
Offline Offline

Сообщений: 345


Просмотр профиля
« Ответ #8 : Февраль 09, 2018, 11:43 »

У вас packet_byte_count это размер одного пакета посылаемых write или это я как бы должен посчитать при отправке с сервера предварительно размер всех пакетов. Ведь я буду делать write в цикле for
Записан
koldun90
Крякер
****
Offline Offline

Сообщений: 345


Просмотр профиля
« Ответ #9 : Февраль 09, 2018, 11:47 »

Код
C++ (Qt)
   while ( !stream.atEnd() )
 
Я не использую qdatastream. Можно мне условие в цикле заменить?
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #10 : Февраль 09, 2018, 12:29 »

Для каждого пакета вначале вычитывается packet_byte_count - это размер пакета (для каждого пакета свой). Если пакет вычитан, то packet_byte_count обнуляется, если нет - packet_byte_count содержит необходимое количество байт для считывания пакета.

Если не используется QDataStream, то код (с поправками) может выглядеть так

Код
C++ (Qt)
class CommandReader
   : public QObject
{
...
   QTcpSocket socket;
   qint32 packet_byte_count;
};
 
void onReadyRead ()
{
   while ( socket.bytesAvailable() )
   {
       // если читаем размер
       if ( !packet_byte_count )
       {
           if ( socket.bytesAvailable() < sizeof( qint32 ) )
               return;
           stream >> packet_byte_count;
       }
 
       // если читаем содержимое
       if ( socket.bytesAvailable() < packet_byte_count )
           return;
 
       QByteArray bytes = socket.read( packet_byte_count );
       packet_byte_count = qint32();
       ...
    }
}
 
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.37 секунд. Запросов: 22.