Предыдущая версия справа и слева
Предыдущая версия
Следующая версия
|
Предыдущая версия
|
develop:qt:network [2021/10/09 17:48] admin |
develop:qt:network [2021/10/27 04:33] (текущий) admin |
| |
===== Еще пример клиент/сервера ===== | ===== Еще пример клиент/сервера ===== |
В данном примере клиент может передавать сколько угодно информации и в каком угодно порядке, впринципе.\\ | |
Сервер поддерживает **множественное подключение**, для **каждого соединения** создается **собственный контекст**, с собственными **буферами**\\ | Сервер поддерживает **множественное подключение**, для **каждого соединения** создается **собственный контекст**, с собственными **буферами**\\ |
| |
При передаче, данные делятся на пакеты дважды, типа программные и физические.\\ | При передаче, данные делятся на пакеты дважды, типа программные и физические.\\ |
**Программные** формируются при каждом вызове метода **write()**, в начало такого пакета автоматом добавляется **числовое значение**, содержащее **размер** передаваемого программного **пакета**.\\ | **Программные** формируются при каждом вызове метода **write()**, если писать через **QDataStream** в **QByteArray**, то перед каждой записью в датастрим будет автоматом добавлено интовое значение, с указанием размера записываемых данных.\\ |
**Физические** формируются уже на транспортном уровне, чаще всего для них отводится 65 535 байт (его размер хранится в двухбайтовом поле заголовка т.е. само это поле может содержать максимум такое значение), размер может меняться по согласованию сторон, содержится в TCP заголовках.\\ | |
| |
Непонятно правда как быть с большими файлами. 20гб точно не передает.\\ | **Физические** формируются уже на транспортном уровне, чаще всего для них отводится 65 536 байт (его размер хранится в двухбайтовом поле заголовка т.е. само это поле может содержать максимум такое значение), размер может меняться по согласованию сторон, содержится в TCP заголовках.\\ |
| |
| Передача ведется потоковая, сначала идет служебная инфа, с указанием размера в т.ч., затем все остальное принимаем как содержимое файла, пока не достигнем указанный размер файла.\\ |
| |
| Служебную инфу пишем с помощью датаСтрим, что бы был указан размер этого "программного" пакета, и чтобы нам вырезать точное кол-во байт, занимаемое этой служебной инфой, содержимое файла просто читаем пока не достигнем указанного размера.\\ |
| |
| Cчитывание 4ех байт остается корректным до тех пор пока программный пакет < 4gb, т.к. в эти 4 байта умещено интовое значение, которое принимает максимум 4 млрд.. байтов ~ 4gb.\\ |
| Если программный пакет будет больше, мы просто некорректно считаем значение его размера и следовательно сам пакет не сможем принять (будет '-1')\\ |
| |
<details> | <details> |
<summary>:!: Пример: Сервер</summary> | <summary>:!: Пример: Сервер</summary> |
| |
| |
sserv.h | sserv.h |
<code cpp-qt> | <code cpp-qt> |
:?: Запись можно делать из файла сразу в метод **write()**, без создания дополнительных **QByteArray** и **QDataStream**, как было в прошлых примерах.\\ | :?: Запись можно делать из файла сразу в метод **write()**, без создания дополнительных **QByteArray** и **QDataStream**, как было в прошлых примерах.\\ |
**write()** принимает **QByteArray**, метод **read()** возвращает **QByteArray**, для записи служебных данных можно сделать отдельный метод для конвертации, вот тут та и понадобится **QDataStream**, который корректно запишет нужные данные в **QByteArray**.\\ | **write()** принимает **QByteArray**, метод **read()** возвращает **QByteArray**, для записи служебных данных можно сделать отдельный метод для конвертации, вот тут та и понадобится **QDataStream**, который корректно запишет нужные данные в **QByteArray**.\\ |
| :?: Что касается **проверки и установления** коннекта:\\ |
| в нашем случае сокет может быть в след состояниях:\\ |
| **0** - не подключен - нужно **вызвать коннект**\\ |
| **1,2** - выполняет поиск и начал устанавливать соединение - соединения еще нет, но и делать вроде ничего не надо, правда неизвестно может ли оно быть зависшим в этот состоянии ?, думаю тут- **ничего не делать**\\ |
| **3** - установленно - **ничего не делать**\\ |
| **6** - вот вот закроется - т.е. запрошен дисконнект, ожидается отправка очереди данных и коннект захлопнется, в таком случае явно нужно снова **вызвать коннект**\\ |
| |
| Что касается отправки файла, пишем данные кусками в метод **write()**, он возвращает кол-во записанных байт, это кол-во отнимаем от размера файла, так управляем циклом\\ |
| В случае ошибки, **write()** возвращает **-1** и все идет по п#зде, поэтому необходимо проверять значение пред тем как с ним работать (отнимать от общем суммы)\\ |
| Так же, после вызова **write()** и до фактической отправки данных нужно какое то время, до этого данные копятся в буфере (видно в **bytesToWrite()**), если писать в цикле то данные **не успевают** уходить в **заполняют буфер** до талого, поэтому нужен метод **wait()**, либо сигнало/слот можно прикрутить какой нибудь\\ |
| |
| Данные **пишутся** так же **пакетами**, как были записаны в **write()**, по одному после каждого **wait()**\\ |
| Если нет коннекта, данные не уходят, **bytesToWrite()** не очищается, последующие вызовы **write()** возвращают **-1**, **wait()** возвращает **false**\\ |
| |
| |
| |
</code> | </code> |
</details> | </details> |
| |
| |
| |
| |