Асинхронная работа с TCP

Делись идеей, получай поддержку и критику!
Aleksandr

Gold
user
user
Сообщения: 97
Зарегистрирован: 21 июн 2011, 15:05
Награды: 1
Версия LabVIEW: 2009-2017
Откуда: Novosibirsk
Контактная информация:

Re: Асинхронная работа с TCP

Сообщение Aleksandr »

Borjomy_1 писал(а):Т.е вместо того, чтобы использовать сбор пакетов операционной системой, предлагается изобретать велосипед и вручную отслеживать дополнительно созданный буфер
Вообще-то так и делается в нормальных продуктах. Буфер ОС существует для других целей, а не для накопления "пакетов", определённых протоколом прикладного уровня.
Не думаете же Вы, что mp3 файл (размером 10 Мб), который вы качаете браузером по протоколу http, хранится в буфере ОС пока не скачаются все 10 Мб?
Borjomy_1 писал(а):под LabView работа со строками предполагает выделение памяти под строку при каждой операции, в результате чего невозможно организовать честный строковый буфер постоянного размера?
Ну так не используйте в качестве буфера строку. Буфер фиксированного размера - это не проблема в LabVIEW.
Borjomy_1 писал(а):Сложно добавить в событие размер пакета, это событие вызвавшего?
(Для уточнения терминоголии.)
Никаких "пакетов" на данном этапе не рассматривается. Пакеты TCP и протоколов более низкого уровня пользователей не интересуют. А о протоколе прикладного уровня библиотека ничего не знает (и не должна знать ни при каких условиях, т.к. она, в данном смысле, универсальная).
(Если Вы имели ввиду размер данных, доступных для чтения, в буфере ОС...)
Теоретически - возможно, если ОС предоставляет такие средства. Практически - сложно или невозможно. В любом, случае, это бессмысленно, потому что в момент времени между проверкой этого размера и чтением данных могут появиться новые данные, которые желательно считать вместе со старыми.
Borjomy_1 писал(а):Операционная система Windows не является операционной системой реального времени. Между окончанием считывания блока данных и командой Continue tracking может пройти неопределенное количество времени.
Очевидно, да.
Borjomy_1 писал(а):Можно получить пропуск события прихода пакета.
Нет. Если в промежуток времени между окончанием считывания блока данных и командой Continue tracking придут данные, то событие будет сгенерировано после выполнения команды Continue tracking. Данные из буфера ОС никуда не денутся.
Uniscan Research
Borjomy_1

Activity Professionalism Silver
doctor
doctor
Сообщения: 2207
Зарегистрирован: 28 июн 2012, 09:32
Награды: 3
Версия LabVIEW: 2009..2020
Откуда: город семи холмов
Благодарил (а): 27 раз
Поблагодарили: 26 раз

Re: Асинхронная работа с TCP

Сообщение Borjomy_1 »

Никаких "пакетов" на данном этапе не рассматривается. Пакеты TCP и протоколов более низкого уровня пользователей не интересуют. А о протоколе прикладного уровня библиотека ничего не знает (и не должна знать ни при каких условиях, т.к. она, в данном смысле, универсальная).
(Если Вы имели ввиду размер данных, доступных для чтения, в буфере ОС...)
Тогда событие ЧЕГО у вас генерируется?
В любом, случае, это бессмысленно, потому что в момент времени между проверкой этого размера и чтением данных могут появиться новые данные
и
Если в промежуток времени между окончанием считывания блока данных и командой Continue tracking придут данные, то событие будет сгенерировано после выполнения команды Continue tracking.
вы сами себе противоречите. Если событие может быть сгенерировано, то, очевидно, должна быть информация о том, какие данные вызвали это событие.

Согласитесь, гораздо удобнее, получив событие, ЗНАТЬ, сколько пришло данных. А не гадать, определяя размер массива данных исключительно одним способом - вычитыванием его из буфера. Тем более, что Immediate не всегда применим (он не является стандартным способом работы).
Не думаете же Вы, что mp3 файл (размером 10 Мб), который вы качаете браузером по протоколу http, хранится в буфере ОС пока не скачаются все 10 Мб?
Я думаю, что размер буфера TCP соединения определяется автоматически и верхний предел явно не определяется. Поэтому в случаях, когда идет потоковая передача данных, возможно достижение размера буфера ОС, близкое к 10Мб. Мало того - есть такая библиотека для работы с MySQL (для примера). В ней выполнение запроса завершается приемом данных (выбранная таблица), Так вот операция чтения - это вычитывание длины (long) и последущее чтение строки данной длины (режим чтения Standart). Передача может длиться десятки секунд и это выдается потом одной строкой. Где хранятся принятые данные в течение установленного таймаута? А таймауты там достигают нескольких минут. И все эти данные вполне легально сваливаются в приемный буфер ОС.
Aleksandr

Gold
user
user
Сообщения: 97
Зарегистрирован: 21 июн 2011, 15:05
Награды: 1
Версия LabVIEW: 2009-2017
Откуда: Novosibirsk
Контактная информация:

Re: Асинхронная работа с TCP

Сообщение Aleksandr »

Borjomy_1 писал(а):Тогда событие ЧЕГО у вас генерируется?
Ранее Вы правильно поняли:
Borjomy_1 писал(а):Получается ситуация: я получаю событие, что в буфере есть массив данных, размером, отличным от нуля.
Aleksandr писал(а):Абсолютно верно.
Borjomy_1 писал(а):вы сами себе противоречите. Если событие может быть сгенерировано, то, очевидно, должна быть информация о том, какие данные вызвали это событие.
В этом нет противоречия. Как раз информация о том, какие данные вызвали это событие, совершенно не важна.
Приход события означает, что в буфере ОС есть данные (размером больше нуля). Т.е. данные (некоторого неопределённого размера) можно прочитать (в режиме Immediate) быстро, не блокируясь на неопределённое время.
Borjomy_1 писал(а):Immediate не всегда применим (он не является стандартным способом работы)
Расскажите, пожалуйста, в каких это случаях неприменим Immediate?
Borjomy_1 писал(а):Согласитесь, гораздо удобнее, получив событие, ЗНАТЬ, сколько пришло данных.
Если после прочтения всего поста это останется актуальным, приведите, пожалуйста, пример, когда это удобнее? Тогда я, скорее всего, смогу Вам указать, чем такой пример плох с точки зрения архитектуры реального приложения.
Borjomy_1 писал(а):А не гадать, определяя размер массива данных исключительно одним способом - вычитыванием его из буфера.
К счастью, гадать ничего не приходится, т.к. перед вызовом функции достаточно информации, что данных вернётся не больше, чем Вы запросили (параметр bytes to read функции TCP Read). А после вызова функции мы уже знаем точный размер полученных данных.
Borjomy_1 писал(а):Где хранятся принятые данные в течение установленного таймаута?
Гарантирую, что в Вашем примере принятые данные хранятся в течение установленного таймаута не в буфере ОС, а в буфере библиотеки, куда она (библиотека) их сохраняет по мере получения. Как я уже писал, так делается в любых нормальных продуктах.

К сожалению, я плохо описал библиотеку в первом посте.
Похоже, что Вы ищите в данной библиотеке то, чего в ней нет и не должно быть. Это достаточно низкий уровень работы с сетью. Её функция - это мультиплексирование ввода-вывода. Его, насколько я знаю, не хватает в LabVIEW, поэтому библиотека и пишется.

Возможно, мы с напарником напишем библиотеку более высокого уровня с [crossed]блэкджеком и .[/crossed] пакетами и их размерами, использующую данную библиотеку, и она Вам понравится.
Uniscan Research
Borjomy_1

Activity Professionalism Silver
doctor
doctor
Сообщения: 2207
Зарегистрирован: 28 июн 2012, 09:32
Награды: 3
Версия LabVIEW: 2009..2020
Откуда: город семи холмов
Благодарил (а): 27 раз
Поблагодарили: 26 раз

Re: Асинхронная работа с TCP

Сообщение Borjomy_1 »

Даже в тестовом приложении вы использовали стандартный режим. И в этом режиме поток, обрабатывающий события, встанет в случае сбоя по одному из клиентов. Безусловно, когда всё работает нормально, таких проблем быть не должно. Однако при создании стандартной библиотеки вы должны осознавать, что настоящие проблемы начинаются, когда не всё работает нормально. И необходимо, чтобы проблемы были локализованы, не влияли на работу других компонентов.
перед вызовом функции достаточно информации, что данных вернётся не больше, чем Вы запросили
А если меньше? Встаем до таймаута и останавливаем остальные соединения?

Как-бы то ни было, но использование TCP Read/Write нескольких соединений в одном потоке, принципиально нехорошая идея. Тем более, что вы отдаете это на откуп пользователям вашей библиотеки. А делегирование события в потоки отдельных клиентов лишает смысла вашу библиотеку. И остается единственная задача - это управление списком активных соединений.

В случае с Immediate существуют определенные программные проблемы, это режим хорош, когда принимаются данные малого размера, меньше одного пакета, но точный размер неизвестен. В противном случае количество принятых пакетов предсказать невозможно. И поэтому для приема больших блоков данных используется режим Standart, который позволяет уменьшить размер кода и, соответственно, ошибок.

Что вам мешает обернуть цикл приема данных в класс и дальше уже отдавать не событие, а уже считанные данные, с размером (к примеру) и идентификатором процесса?
AndreyDmitriev

Activity Professionalism Tutorials Gold Black
VIP
VIP
Сообщения: 1326
Зарегистрирован: 03 фев 2010, 00:42
Награды: 6
Версия LabVIEW: 6.1 - 2024
Откуда: Германия
Благодарил (а): 1 раз
Поблагодарили: 36 раз
Контактная информация:

Re: Асинхронная работа с TCP

Сообщение AndreyDmitriev »

Borjomy_1 писал(а):ИМХО - слишком сложно, медленно и с дополнительным расходом памяти. И только из-за нежелания каждого клиента выделять в отдельный поток.
Вот вы, коллега Borjomy_1, (а также в лёгкой степени Иван и Андрей), зачем-то подвергли коллегу Александра какой-то незаслуженной критике, либо очень уж бегло и поверхностно посмотрели что там внутри. На самом деле там достаточно аккуратно всё сделано и есть класс задач, где подобное решение вполне имеет право на жизнь. В основном - это применимо, если у нас открывается очень много (читай-тысячи) соединений (обычно на один и тот же порт).
Если мы программируем это дело на чистом LabVIEW, то нам в общем случае придётся динамически запустить соответствующее количество инструментов (где-то на форуме уже был пример на основе асинхронного вызова). Я не поленился и проверил - если открывать 4000 соединений, то чистое решение LabVIEW сожрёт аккурат 200 мегабайт памяти. Там, конечно, можно повозиться, но тем не менее формально расход памяти при классическом LabVIEW подходе будет выше, нежели в предложенном решении. Данное решение при открытии 4000 соединений требует примерно 60 МБ памяти (я сгенерил два простеньких приложения и смотрел занимаемый в памяти размер). При увеличении количества соединений расход памяти в данном решении будет расти незначительно (грубо говоря один хэндл на клиента), а при чистом LabVIEW - будет расти пропорционально количеству клиентов (один подприбор на клиента).

С точки зрения архитектуры и отладки - такой подход тоже несколько удобнее и "прозрачнее", нежели динамически вызываемые инструменты.

Лёгкие недостатки тоже есть:
Данный метод чуть медленнее - на приём-передачу 4000 последовательных сообщений чистый LabVIEW затратил 12 секунд, а этот метод - 19. Тут это связано по видимому с форвадингом события в ивент структуру. Впрочем, не видя кода самой DLL сложно говорить о том, можно тут побороться за скорость или нет. С другой стороны, попытка отправить 4000 сообщений параллельно классическому LabVIEW решению привела к зависанию компьютера минуты на полторы примерно на шестисотом сообщении. Тут оно понятно - сотни приборов в памяти почти одновременно проснулись, и планировщик LabVIEW лихорадочно заметался между ними. То есть при создании высоконагруженного приложения всё равно придётся возиться с балансировкой нагрузки. А предложенное решение вполне справится с такой ситуацией.

Понятно, что если все события заводятся в одну event структуру, то и обрабатываться они будут последовательно. В принципе ничто не мешает сделать мультипоточность, но это потребует определённых изменений. Первое, что приходит в голову - пробросить ивенты в несколько очередей (тут у меня есть здоровые сомнения про continue tracking), но тут также желательно обойтись без дуплицирования кода и сделать универсальный обработчик, в итоге мы придём обратно к классическому LabVIEW решению. Можно раскидать слушателей по потокам на этапе инициализации. Вообще я бы использовал эту библиотеку именно в случае, когда клиентов очень много, но траффик от каждого невелик, что позволяет обрабатывать все запросы последовательно.

По мелочи:
- абсолютный путь при подключении DLL не есть хорошо, при открытии вываливается соответствующее сообщение.
- необходимости класса я вот как-то не вижу, хватило бы функциональной переменной, но тут уж - хозяин-барин.
- исходник библиотеки DLL тоже хотелось бы видеть (тем более что многие уже переехали на x64)
- Create Listener и Wait on listener можно смело засунуть в класс.

Я мог бы ещё поспорить про 7z и потоки в LabVIEW, но совсем уж в оффтопик скатываться не буду. А топикстартеру - спасибо.
Аватара пользователя
IvanLis

Activity Professionalism Tutorials Gold Man of the year 2012
Автор
guru
guru
Сообщения: 5458
Зарегистрирован: 02 дек 2009, 17:44
Награды: 7
Версия LabVIEW: 2015, 2016
Откуда: СССР
Благодарил (а): 27 раз
Поблагодарили: 86 раз

Re: Асинхронная работа с TCP

Сообщение IvanLis »

--- off top ---
AndreyDmitriev писал(а):Вот вы, коллега Borjomy_1, (а также в лёгкой степени Иван и Андрей), зачем-то подвергли коллегу Александра какой-то незаслуженной критике, либо очень уж бегло и поверхностно посмотрели что там внутри.
"Здоровая" критика всегда идет на пользу.
Что касается меня, то я не пытался критиковать, вопросы били нацелены в первую очередь, что бы самому разобраться, в каком случае данный инструмент можно использовать и как...
Что бы не получилось, что взял в руки "лопату" и пошел копать "асфальт". Результата нет, "лопату" угробил и разочаровался в конструкторе.

Любая работа заслуживает уважения, там более такая :wink: .
Нужно только доступно объяснить: где, когда и как использовать данный инструмент.

Удачи автору в работе.
Надеюсь, что такая бурная реакция не испугает его, а наоборот подвигнет на дальнейшую работу и его библиотека найдет своих благодарных пользователей :drink: .
AndreyDmitriev

Activity Professionalism Tutorials Gold Black
VIP
VIP
Сообщения: 1326
Зарегистрирован: 03 фев 2010, 00:42
Награды: 6
Версия LabVIEW: 6.1 - 2024
Откуда: Германия
Благодарил (а): 1 раз
Поблагодарили: 36 раз
Контактная информация:

Re: Асинхронная работа с TCP

Сообщение AndreyDmitriev »

IvanLis писал(а): Что касается меня, то я не пытался критиковать,
...
Нужно только доступно объяснить: где, когда и как использовать данный инструмент.
Это я всех под одну гребёнку, уж извиняйте.

На самом деле Александр адресуется вот к этой проблеме:

http://ru.wikipedia.org/wiki/%D0%9F%D1% ... 0%B8%D0%B9

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

Оффтопик:
Пока лазил по википедии, наткнулся на замечательную (хотя в чём-то спорную) цитату Алана Кокса:
«Компьютер — это конечный автомат. Потоковое программирование нужно тем, кто не умеет программировать конечные автоматы». :D
Borjomy_1

Activity Professionalism Silver
doctor
doctor
Сообщения: 2207
Зарегистрирован: 28 июн 2012, 09:32
Награды: 3
Версия LabVIEW: 2009..2020
Откуда: город семи холмов
Благодарил (а): 27 раз
Поблагодарили: 26 раз

Re: Асинхронная работа с TCP

Сообщение Borjomy_1 »

Ну мне тоже интересно, в каком качестве использовать данную библиотеку. Она интересна в качестве софтового сервера, без привязки к аппаратной платформе. Я же исходил из надежности работы с гарантированным откликом. 4 тысячи коннектов, согласитесь, слишком узкая ниша. А с десятком коннектов и классическая реализация прекрасно работает. И большинство задач работы с оборудованием предполагает двунаправленный обмен (желательно, с минимальным временем отклика), для чего данная библиотека не удобна. Тем более, что декларируется именно асинхронный режим работы. Но это не так. Режим работы как раз зависимый, на несколько ядер процессора не масштабирован. Ну и в чем заявленная асинхронность?

Вот есть "нерешенная" задача управления настройками удаленных устройств. Чтобы из потока GUI отдавалась команда по TCP, которая выполнялась бы асинхронно от основного потока и возвращала результат с контролем таймаута. Такой реализации в :labview: нет... и каждый раз надо заново это писать. А руки "универсальную" библиотеку сделать не доходят.
AndreyDmitriev

Activity Professionalism Tutorials Gold Black
VIP
VIP
Сообщения: 1326
Зарегистрирован: 03 фев 2010, 00:42
Награды: 6
Версия LabVIEW: 6.1 - 2024
Откуда: Германия
Благодарил (а): 1 раз
Поблагодарили: 36 раз
Контактная информация:

Re: Асинхронная работа с TCP

Сообщение AndreyDmitriev »

Borjomy_1 писал(а):декларируется именно асинхронный режим работы. Но это не так. Режим работы как раз зависимый, на несколько ядер процессора не масштабирован. Ну и в чем заявленная асинхронность?
Асинхронность тут чуть иного рода. Вы путаете асинхронность с многопоточностью. В данном случае поток, ожидающий данных с множественных соединений, не блокируется этими данными. При поступлении данных он лишь уведомляет поток обработчика о том, что что-то пришло, а сам продолжает ожидать новых данных - в этом смысле поток, наблюдающий за приходящими данными (единственный) не блокируется обработкой данных, а это и есть асинхронность.

Ну как если бы мы на Си написали что-то типа:

while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

Обработка сообщений же ставится в очередь посредством event структуры. Примерно так, кстати, поступает и Windows со своей очередью сообщений.

В любом случае, при примении того иного подхода следует всегда отталкиваться от задачи, которую надо решить.
Эта библиотека позволяет довольно удобно завести уведомления о поступивших данных (при этом не читая сами данные) в event структуру, собрав их в одном месте, либо разбросав затем по необходимому количеству потоков (меньшему, нежели количество соединений) - и это может оказаться применимо в некоторых случаях.
Ответить
  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Проекты»