Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Отправка UDP по разным адресам через один сокет


Страницы:   1 2 3

Добежал ©   (2009-01-29 16:03:00) 

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

Как сделано сейчас: все общение с сокетом синхронизировано. То есть, поток входит в синхронизирующую секцию, отправляет данные, ждет и принимает данные (используется функция Select), выходит из критической секции. Соответственно, на время общения одного потока другие потоки ждут.

Что нужно сделать: распараллелить работу. Ведь UDP позволяет отправлять в одно и тоже время по разным адресам пакеты.

Мои соображения: с отправкой проблем нету, каждый из потоков вызывает SendTo с нужными ему параметрами - не вопрос.
А вот с приемом возникают проблемы... Допустим, поток ставит Select на нужный сокет, событие срабатывает... Но ведь это может быть пришел ответ для другого потока. Причем поскольку каждый поток ставит Select, то все определяется тем кто из потоков раньше сделает recv. Притом, что полученные данные могут предназначаться не тому потоку, который раньше всех успел сделать recv. Способ откидывается.

Я придумал только ввод некоего обслуживающего сокет потока. Он постоянно выгребает данные, пришедшие сокету и складывает их в какой-то синхронизированный буфер.
Сетевые потоки тогда работают так: посылают запрос с помощью SendTo, а потом начинают мониторить синхронизированный буфер... Вопрос только в том, как они его будут мониторить?!
Создавать на каждый такой запрос данных свой объект ядра, служащий синхронизатором для ответа именно данному потоку? Как-то нерационально на мой взгляд. Выжидать константное время и проверять в буфере появился ли ответ? Тогда не экономно, так как ответ может появится гораздо раньше, излишнее ожидание.

Есть еще и прочие проблемы - допустим, поток по таймауту не дождался ответа, "ушел". А ответ все таки пришел и был помещен обслуживающим потоком в синхронизированный буфер. Так и будет этот ответ висеть получается? Ведь ожидающий эту информацию поток уже ушел...

Как обычно все организовывается в данных ситуациях? Есть ли замечания по моей логике?

P.S. Дополнительный вопрос - является ли вызов методов SendTo и recv потокобезопасными для socket'а?


Slym   (2009-02-03 04:32:00) [1]

Удалено модератором


Piter   (2009-02-02 23:14:00) [2]

Удалено модератором


Piter   (2009-02-02 23:14:00) [3]

Удалено модератором


Сергей М.   (2009-02-02 22:47:00) [4]

Удалено модератором


Piter   (2009-02-02 22:32:00) [5]

Удалено модератором


Сергей М.   (2009-02-02 22:24:00) [6]

Удалено модератором


Piter   (2009-02-02 22:15:00) [7]

Slym ©   (02.02.09 19:13) [35]
сделай "чтоб работало", оптимизировать потом будешь...
время создания евента ничтожно по сравнению с временем убитым на грамотную организацию пула :)


Да я в общем переживаю не за время создания event'а, а за WaitForSingleObject. Если эвент занят, то поток уходит в режим ядра для засыпания, на это тратится немало тактов. С другой стороны, с современными процессорами это и не замечишь.

Просто хочется сделать нормально и забыть о транспорте.


Slym   (2009-02-02 19:13:00) [8]

Добежал   (02.02.09 10:32) [33]
сделай "чтоб работало", оптимизировать потом будешь...
время создания евента ничтожно по сравнению с временем убитым на грамотную организацию пула :)


Добежал   (2009-02-02 13:44:00) [9]

Удалено модератором


Добежал   (2009-02-02 10:32:00) [10]


> можно не постоянно креатить евенты а держать пул евентов

ну да, наверное так и сделаю. Спасибо!


Slym   (2009-02-02 05:28:00) [11]

можно не постоянно креатить евенты а держать пул евентов


Slym   (2009-02-02 05:26:00) [12]

Добежал   (30.01.09 17:54) [28]
можно сразу в блокирующий метод обрамить код:


ClientTable - поля (Event,IP,Port,Msg);
TRec=record
Event,IP,Port,Msg
end;

function Transport.Send(const Msg,IP:string;Port:word;TimeOut:longint):string;
begin
 result:='';
 Event:=CreateEvent;
 try
   ClientTable.Add(Event,IP,Port);
   Socket.send(Msg,IP,Port);
   if WaitForSingleObject(Event,TimeOut)=OK then
     result:=ClientTable.GetMsg(Event);
 finally
   ClientTable.Remove(Event);
   CloseObject(Event);
 end;
 CloseHandle(Event);
end;

procedure OnSocket.Recv(RemoteIP,RemotePort,Data);
var Record:TRec;
begin
 if ClientTable.FindRecord(RemoteIP,RemotePort,var Record) then
 begin
   Record.Msg:=Data;
   SetEvent(Record.Event);
 endl
end;

procedure Thread.Execute
begin
 while not Terminated do
 begin
   s:=Transport.send('Hello!','192.168.1.1',666,TimeOut);
   if length(s)<>0 then
    Writeln(s);
 end;
end;

Доступ к ClientTable и Socket должен быть заключен в критическую секцию


Сергей М.   (2009-01-30 19:35:00) [13]

Удалено модератором


Сергей М.   (2009-01-30 19:33:00) [14]

Удалено модератором


Добежал   (2009-01-30 17:54:00) [15]

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


> Решение задачи возможно только при следующих условиях -
> уникальности и точной идентификации входящих пакетов!

такое условие есть.


> потоки передают сообщение, адресат (IP:PORT) и объект для
> ответа (колбек функция, объект синхронизации (евент)) транспортному
> потоку

вот тут начинаются проблемы. Система плагиновая DLL, поэтому потоков от сторонних плагинов может быть сколько угодно, может быть они вызовут транспорт один раз, а может будут вызывать постоянно. Соответственно, или на каждый запрос каждый раз создавать объект синхронизации и потом его удалять, или на каждый ID потока создавать свой объект синхронизации, а при каждом запросе искать его в таблице - вопрос тогда, когда и кем финализировать объекты синхронизации.
И нельзя ли сделать как-то оптимальнее.


Добежал   (2009-01-30 17:34:00) [16]

Удалено модератором


Slym   (2009-01-30 17:28:00) [17]

по типу NAT таблицы и преобразования пакетов


Slym   (2009-01-30 17:27:00) [18]

Как обычно вода в ступе...
Не ветка помойка...
По сабжу...
Решение задачи возможно только при следующих условиях - уникальности и точной идентификации входящих пакетов!
Т.е. если отдельная задача тебует общения с устройством с уникальной парой RemoteIP:RemotePORT!

потоки передают сообщение, адресат (IP:PORT) и объект для ответа (колбек функция, объект синхронизации (евент)) транспортному потоку

send(msg:string;ip:string;port:word;callback:procedure)

травспортный поток заносит в свою внутреннюю таблицу ключ IP:PORT и соответствующий ему объект от
IP:port=callback
и отправляет сообщение...
при приходе ответа в таблице по ключу RemoteIP:RemotePort ищется калбек и при нахождении вызывается с принятым сообщением


Сергей М.   (2009-01-30 17:03:00) [19]


> событие придется создавать не на поток, а на каждый запрос


Объект синхронизации, если уж на то пошло, достаточно создавать по одному на каждый прикладной поток, причем его созданием вполне может заняться сам прикладной поток.

Транспортный поток создает объект-очередь передачи, доступный всем прикл.потокам.

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

Трансп.поток берет из очереди передачи сообщения и посылает их адресатам.
По мере поступления ответных сообщений трансп.поток "сортирует" их на предмет принадлежности ответов тем или иным прикл.потокам, помещая их в соответствующие очереди вх.сообщений и переводя соотв. объект синхр-ции в сигнальное состояние.

Прил.потоки ждут каждый своего сигнала, после чего выгребают свои очереди и сбрасывают сингал.

Все !

Можно и без объектов синхронизации обойтись - прикл.потоки сообщают всем заинтересованным потокам свои идентификаторы и попросту засыпают, если им нечего передавать или очереди приема пусты. Достаточно разбудить прикл.поток для того чтобы он возобновил свой прикладной цикл.


Anatoly Podgoretsky   (2009-01-30 16:51:00) [20]

> Добежал  (30.01.2009 16:48:22)  [22]

Метод Synchronize


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо