![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Отправка UDP по разным адресам через один сокет
Добежал © (2009-01-29 16:03:00)Есть один открытый UDP-сокет, через него разные потоки выполняют свое общение. Общение по типу запрос-ответ, делается запрос, ждется ответ, потом поток "уходит" со своим ответом.
Как сделано сейчас: все общение с сокетом синхронизировано. То есть, поток входит в синхронизирующую секцию, отправляет данные, ждет и принимает данные (используется функция Select), выходит из критической секции. Соответственно, на время общения одного потока другие потоки ждут.
Что нужно сделать: распараллелить работу. Ведь UDP позволяет отправлять в одно и тоже время по разным адресам пакеты.
Мои соображения: с отправкой проблем нету, каждый из потоков вызывает SendTo с нужными ему параметрами - не вопрос.
А вот с приемом возникают проблемы... Допустим, поток ставит Select на нужный сокет, событие срабатывает... Но ведь это может быть пришел ответ для другого потока. Причем поскольку каждый поток ставит Select, то все определяется тем кто из потоков раньше сделает recv. Притом, что полученные данные могут предназначаться не тому потоку, который раньше всех успел сделать recv. Способ откидывается.
Я придумал только ввод некоего обслуживающего сокет потока. Он постоянно выгребает данные, пришедшие сокету и складывает их в какой-то синхронизированный буфер.
Сетевые потоки тогда работают так: посылают запрос с помощью SendTo, а потом начинают мониторить синхронизированный буфер... Вопрос только в том, как они его будут мониторить?!
Создавать на каждый такой запрос данных свой объект ядра, служащий синхронизатором для ответа именно данному потоку? Как-то нерационально на мой взгляд. Выжидать константное время и проверять в буфере появился ли ответ? Тогда не экономно, так как ответ может появится гораздо раньше, излишнее ожидание.
Есть еще и прочие проблемы - допустим, поток по таймауту не дождался ответа, "ушел". А ответ все таки пришел и был помещен обслуживающим потоком в синхронизированный буфер. Так и будет этот ответ висеть получается? Ведь ожидающий эту информацию поток уже ушел...
Как обычно все организовывается в данных ситуациях? Есть ли замечания по моей логике?
P.S. Дополнительный вопрос - является ли вызов методов SendTo и recv потокобезопасными для socket'а?
Добежал (2009-01-30 16:48:00) [21]
> Потому что это сервер, создающий для каждого клиента отдельное
> TCP-соединение
и что дальше? А сам протокол верхнего уровня HTTP синхронный. И у меня протокол верхнего уровня синхронный. И ты пишешь, что это бред. Ну иди заяви, что протокол HTTP тоже бред.
Я не спрашиваю как мне идентифицировать устройства. Я спрашиваю как лучше синхронизировать выборку сообщений. Вопрос ИМЕННО В ЭТОМ.
Если ты хочешь сказать, что это невозможно сделать - то это неправда. Я уже предложил способ, как это можно сделать. И вопрос в том, насколько оптимален этот способ и можно ли сделать лучше.
Сергей М. (2009-01-30 16:35:00) [22]
> почему же тогда Apache в одно время может общаться с тысячами
> клиентов, а?
Потому что это сервер, создающий для каждого клиента отдельное TCP-соединение.
А у тебя UDP, который НЕ подразумевает соединение !
Так что не надо сравнивать кислое с пресным, добежавший ты наш)
Anatoly Podgoretsky (2009-01-30 16:27:00) [23]В потоках конечно проще использовать синхронные методы, но ты то не умеешь работать с потоками, видимо реализовал по схеме Архангельского.
Anatoly Podgoretsky (2009-01-30 16:26:00) [24]
> Протокол HTTP точно также синхронный.
Неправда
Добежал (2009-01-30 15:29:00) [25]
> Создать событие на поток - это не расточительство
так в том и дело, что событие придется создавать не на поток, а на каждый запрос. Из-за плагиновой системы предсказать сколько потоков гипотетически могут вызвать транспортные функции - невозможно.
Добежал (2009-01-30 15:26:00) [26]
> Притом что синхронный протокол подразумевает схему :
слушай, не нужно вырывать слово из контекста. Я не задавал вопрос "причем здесь асинхронность протокола", я задавал вопрос: "причем здесь асинхронность протокола, если общение идет с разными клиентами?".
Протокол HTTP точно также синхронный. Но почему же тогда Apache в одно время может общаться с тысячами клиентов, а?!
По старой привычке вместо того, чтобы помочь решить проблемы, ты продолжаешь докапываться к словам, причем чем дальше тем делая это все более неумело. Каждый поток приложения общается со СВОИМ устройством по СИНХРОННОМУ ПРОТОКОЛУ и никакой асинхронный протокол тут нафиг не нужно. Проблема одна - что пакеты от разных IP приходят на один порт и нужно синхронизировать чтение приходящих пакетов.
Сергей М. (2009-01-30 14:39:00) [27]
> 2.
Это очепятка
Сергей М. (2009-01-30 14:38:00) [28]
> причем здесь асинхронность протокола
Притом что синхронный протокол подразумевает схему :
1. Отправка запроса
2. Ожидание ответа на предыдущийзапрос
3. Прием/обработка ответа на предыдущийзапрос
4. goto 1
Асинхронный же подразумевает иную схему:
1. Отправка одного или более маркированныхзапросов, если таковые имеются во вх.очереди.
2. Таймаут-ожидание ответа на любой из отправленных запросов, при таймауте goto 1
3. Прием и диспетчеризация ответа на конкретныйранее когда-либо отправленный запрос.
4. goto 1
2.
Вариант (2009-01-30 14:15:00) [29]
> Мне нужно конкретика по тому, как организовать прием данных.
Создать событие на поток - это не расточительство. Тогда ложишь потоку в буфер и сигналишь. Послать сообщение потоку тоже можно (PostThreadMessage).
Добежал (2009-01-30 13:47:00) [30]а причем здесь асинхронность протокола, если общение идет с разными клиентами?
Если так легче - представьте себе много внешних аппаратов, общение идет по UDP. Аппараты умеют отвечать только в жестко заданный порт (хотя ежу понятно, что логичнее отвечать в порт, с которого пришел запрос), у каждого аппарата свой IP. Серверу нужно запросить состояние аппарата, получить ответ.
Anatoly Podgoretsky (2009-01-30 13:45:00) [31]> Сергей М. (30.01.2009 13:36:11) [11]
> не подразумевает асинхронности
И потоковости.
Сергей М. (2009-01-30 13:36:00) [32]
> на время общения одного потока другие потоки ждут
А что им остается делать, если твой прикладной протокол изначально, как я понял, не подразумевает асинхронности ?
Добежал (2009-01-30 11:11:00) [33]Вариант, здорово, конечно, но очевидно.
Протокол уже есть, определен не мной. Задача поставлена.
Я предложил свое решение проблемы - это сделать обслуживающий поток, который постоянно будет выгребать данные из сокета и складывать в общий буфер какой-то. Я обозначил проблему, которую вижу при этом - как сигнализировать исходному потоку о том, что данные получены? На каждый запрос создавать объект ядра? Как-то расточительно.
Ждать константное время и и проверять ответ - неэффективно в плане времени.
Или может есть другие стандартные решения данной проблемы.
А ты описал общую структуру, мне это не нужно. Мне нужно конкретика по тому, как организовать прием данных. А ты описал это одним предложением "Передать структуру данных получателю" :) Вот мне и интересно как это лучше сделать.
Вариант (2009-01-30 06:28:00) [34]
> Добежал (29.01.09 16:03)
Я решаю для себя такую задачу обычно разбив ее на сущности.
Определим логические сущности
1 Транспорт
- отвечает за передачу данных из буфера TX в транспортную среду. Доступ к буферу в случае потоков должен быть синхронизирован. Варианты исполнения буфера - Например TThreadList и о добавлении стуктуры данных -это оповещение событием или сообщением.
Или передача указателя на структуру данных через сообщения. Или что-то другое.....
- отвечает за прием за прием данных в буфер RX из транспортной среды и оповещение Декодера(парсера) о наличии данных в буфере. Варианты реализации примерно такие же как и у буфера TX.
2 Кодер
Задача подготовить структуры данных к передаче в транспортной среде и положить их в TX буфер, оповестить об этом Транспорт
3 Декодер - получив оповещение от Транспорта, что есть данные для приема - забрать их, декодировать по заданному вам алгоритму в ваши структуры данных. Передать структуру данных получателю (как вариант например Потоку работы с БД) Отсюда вытекает, что в случае множества получателей внутри процесса структура данных должна иметь адрес - кому она предназначена, что бы быть потом адресованной нужному получателю. Как это реализовать ?
Вариантов много. Например - связать Декодер еще с одной сущностью.
Введем сущность
4 Протокол. Протоколом может быть - последовательность байт адреса, определенная структура данных, определенные действия, синхронность определенных действий, и еще многое другое... Как распознать, кому отправлены данные и что это за данные, в каком порядке их передавать, что делать в случае тайм-аута, опаздавших сообщений и прочее - задача протокола. Например опаздавшие пакеты я откидываю, а определяю опаздавший пакет по номеру пакета и ID получателя. Вариантов исполнения протокола может быть много.
> P.S. Дополнительный вопрос - является ли вызов методов SendTo
> и recv потокобезопасными для socket'а?
Если я правильно понял вопрос - можно ли вызывать их из разных потоков (разделить передачу и прием) или потока не создавашего сокет?
Для Windows (к сожалению не знаю как работают сокеты в этом случае в других системах, но подозреваю так же) -
да можно разделить прием от передачи по разным потокам. А создателем сокета может быть совсем другой поток.
Сергей М. (2009-01-29 22:40:00) [35]Удалено модератором
Piter (2009-01-29 22:25:00) [36]Удалено модератором
Сергей М. (2009-01-29 22:02:00) [37]
> поток ставит Select на нужный сокет, событие срабатывает
Какое нахрен событие ?
Где в вопросе хоть что-либо напоминающее Winsock-события ?
В топку.
Сергей М. (2009-01-29 22:00:00) [38]
> Piter © (29.01.09 21:48) [4]
> будут открываться различные рандомные локальные UDP-порты
И чего ?
Что в том плохого ?
> по условиям задачи это неприемлимо
Условия, imho, кривыеизначально.
Piter (2009-01-29 21:48:00) [39]Сергей М. © (29.01.09 19:26) [2]
Каждый поток вправе создать своё собственное гнездо
если делать как ты говоришь, то со стороны программы постоянно будут открываться различные рандомные локальные UDP-порты. А по условиям задачи это неприемлимо, нужен один открытый определенный порт.
Сергей М. (2009-01-29 19:27:00) [40]Удалено модератором