Разделение одного реального соединения на несколько
От: Fedorchenko Aleksey Украина  
Дата: 09.06.03 13:12
Оценка:
Возникла потребность создать разделяемый сокет, т.е. чтобы на одном сокете можно было держать несколько сессий и по ним можно было бы гонять разные потоки данных.

Решение в лоб...
Скажем каждой новой сессии дается свой ключ и он известен как клиенту, так и серверу. Далее... По ключу при вычитке определяем для кого предназначены данные и помещаем их во внутренний буфер той сессии. Все хорошо, но...

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

Как быть?
Re: Разделение одного реального соединения на несколько
От: Tom Россия http://www.RSDN.ru
Дата: 09.06.03 14:43
Оценка:
FA>Как быть?
Конкретизировать и более полно описать желаемый результат
... << RSDN@Home 1.0 beta 6a >>
Народная мудрось
всем все никому ничего(с).
Re[2]: Разделение одного реального соединения на несколько
От: Fedorchenko Aleksey Украина  
Дата: 09.06.03 15:00
Оценка:
Попробуем конкретизировать...

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

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

Как хочется сделать... Открыть одно соединение с сервером и пустить через него все модули клиента. Встает проблема создания нескольких независимых сессий на одном сокете. В своем первом посте я немного расписал пути решения с возможными последствиями. Что это в итоге даст? В итоге будет нормальная загруженность сокета с минимальным количеством потоков на его обслуживание и отсутствие нескольких соединений от одного пользователя на сервере.
Re[3]: Разделение одного реального соединения на несколько
От: Tom Россия http://www.RSDN.ru
Дата: 09.06.03 15:54
Оценка: +1
Итак задача определилась — вуртуальный сокет. Решений много. Например ещё один уровень над твоим протоколом или изменения в существуюшем. Принципиальный проблемм тут нет. По поводу буферов. Реализуй вместо безразмерных — циклические (кольцевые). Это стандартное решение в таких ситуациях.
... << RSDN@Home 1.0 beta 6a >>
Народная мудрось
всем все никому ничего(с).
Re[3]: Разделение одного реального соединения на несколько
От: Michael Chelnokov Украина  
Дата: 09.06.03 16:16
Оценка:
FA>Как хочется сделать... Открыть одно соединение с сервером и пустить через него все модули клиента. Встает проблема создания нескольких независимых сессий на одном сокете. В своем первом посте я немного расписал пути решения с возможными последствиями. Что это в итоге даст? В итоге будет нормальная загруженность сокета с минимальным количеством потоков на его обслуживание и отсутствие нескольких соединений от одного пользователя на сервере.

Зря. Выигрыш минимальный, работы по переделке много. Так ли уж необходимо это делать?
А сделать это... Хм... Во многом зависит от того, что из себя представляет этот "собственный протокол". Но, повторюсь, игра не стОит свеч, если Вы описали всё как есть и не забыли упомянуть о каких-то более весомых причинах.
Re[4]: Разделение одного реального соединения на несколько
От: Fedorchenko Aleksey Украина  
Дата: 09.06.03 17:35
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>Итак задача определилась — вуртуальный сокет. Решений много.


От того и спрашиваю

Tom>Например ещё один уровень над твоим протоколом или изменения в существуюшем. Принципиальный проблемм тут нет.


Может быть, но я как раз то и не увидел однозначно хорошего решения. Может Вы подскажете? Код не нужен. Важна идея.

Tom>По поводу буферов. Реализуй вместо безразмерных — циклические (кольцевые).

Tom>Это стандартное решение в таких ситуациях.

Знаю я про циклические буфера (именно о на них и собирался писать внутренние буфера), но только ж это не решает описанную мною проблему монополизации сокета.

Так что? Может распишете подробнее Ваши идеи. Если будут действительно хороши, то адаптировать их под конкретную задачу — дело техники.
Re[4]: Разделение одного реального соединения на несколько
От: Fedorchenko Aleksey Украина  
Дата: 09.06.03 17:42
Оценка:
Здравствуйте, Michael Chelnokov, Вы писали:

MC>Зря. Выигрыш минимальный, работы по переделке много. Так ли уж необходимо это делать?


Выигрыш в:
1 более прозрачной работе (один клиент — одно соединение)
2 меньших расходах на управление сокетами (сейчас для каждого соединения создается свой поток, но при этом загруженность его составляет менее 5%, т.к. время обработки данных куда больше времени передачи результирующих данных)

Зачем мне держать 10 бездействующих потоков, если можно все это отдать одному и нормально его нагрузить? Согласен, что можно управлять и одним потоком всеми сокетами, но проблема незагруженности самого сокета все равно остается!
Re[5]: Разделение одного реального соединения на несколько
От: Polosaty Беларусь  
Дата: 09.06.03 18:50
Оценка:
Здравствуйте, Fedorchenko Aleksey, Вы писали:

FA>Здравствуйте, Michael Chelnokov, Вы писали:


FA>Зачем мне держать 10 бездействующих потоков, если можно все это отдать одному и нормально его нагрузить?

Лучше 10 бездействующих потоков, чем один действующий . Бездействующие потоки (если они действительно бездействующие) ресурсы процессора не потребляют. Поэтому само по себе это не плохо.
FA>Согласен, что можно управлять и одним потоком всеми сокетами, но проблема незагруженности самого сокета все равно остается!
А что плохого в "незагруженности" сокета?
Re[6]: Разделение одного реального соединения на несколько
От: Fedorchenko Aleksey Украина  
Дата: 09.06.03 19:57
Оценка: -2
Здравствуйте, Polosaty, Вы писали:

P>Лучше 10 бездействующих потоков, чем один действующий . Бездействующие потоки (если они действительно бездействующие) ресурсы процессора не потребляют. Поэтому само по себе это не плохо.


P>А что плохого в "незагруженности" сокета?


Неправда Ваша! Даже бездействующий поток отбирает процессорное время, т.к. из таблицы потоков он никуда не убирается, поэтому ядро к нему переключается и лишь после этого видит, что он спящий и идет дальше. Но это немного из другой истории.

А вообще-то все это чрезмерное расходование объектов ядра и если создается mission critical application, то чем лучше (читай сбалансированней) оно загружено, тем лучше!

Однако этот разговор выходит за рамки темы, вернемся к мультиплексированию виртуальных сокетов на одном реальном
Re[7]: Разделение одного реального соединения на несколько
От: Алексей Владимирович Миронов Россия  
Дата: 10.06.03 00:45
Оценка:
Здравствуйте, Fedorchenko Aleksey, Вы писали:

FA>Неправда Ваша! Даже бездействующий поток отбирает процессорное время, т.к. из таблицы потоков он никуда не убирается, поэтому ядро к нему переключается и лишь после этого видит, что он спящий и идет дальше.


Круто Вы описали все операционные системы, существующие и проектируемые. Хороший планировщик неактивные задачи (потоки/процессы, у кого что) переносит в _другой_ список со всеми вытекающими последствиями.

Хотя в чем-то я с Вами согласен: слишком много потоков — плохо. Например, под Windows каждый поток (не важно, активный или нет), отнимает не меньше мегабайта от адресного пространства приложения.
Re: Разделение одного реального соединения на несколько
От: clairbee Россия http://clairbee.void.ru/
Дата: 10.06.03 02:18
Оценка: +1
FA>Возникла потребность создать разделяемый сокет, т.е. чтобы на одном сокете можно было держать несколько сессий и по ним можно было бы гонять разные потоки данных.
FA>Как быть?

Делаешь прослойку в виде еще одного уровня протокола.
Т.е. у тебя будет TCP соединение установленное между двумя хостами.
Каждый connection endpoint будет внутренней переменной у модуля, предоставляющего API для "сессий".

Рекомендуемая схема работы:

В начале работы вызываем функцию инициализации модуля, запускающую ("internal") thread, создающую пайп ("service pipe") и устанавливающую соединение с другой стороной (ради симметрии модулей с обоих сторон следует вспомнить, что по стандарту TCP connect в connect могут установить соединение (следует помнить, что linux (2.2, как минимум) "не знает" про стандарт TCP (WinNT, FreeBSD, Tru64, Solaris, как минимум, знают))).
Internal thread делает select на некоем наборе "set X"+одна из сторон service pipe'а+TCP соединение.

При создании сессии клиент(каждый из "peer"-ов этой сессий) вызывает функцию типа open (и передает ей идентификатор сессии (хоть число, хоть строчка)), которая возвращает дескриптор одной из сторон свежесозданного пайпа, другой конец пайпа добавляет в set X, запоминает соответствие идентификатора этой сессии и пары дескрипторов пайпа, и посылает байтик в service pipe.

Internal thread при получении данных по service pipe'у просто обновляет списк дескрипторов по которым надо делать select.

Клиент работает с полученным дескриптором, как с сокетом (ну типа select, read и write и на пайпе неплохо работают:).

Internal thread при появлении данных на одном из дескрипторов set X, смотрит соответствующие пайпа идентификатору сессии, и посылает по TCP соединению пакетик в каком-то своем внутреннем формате типа (имя сессии+длина+данные прочитанные из пайпа).
При получении данных по TCP разворачиваем пакет, смотрим имя службы, и если находим у себя соответствие имени пайпу, то полученные данные посылаем в пайп.

That's all folks.

Если тупо сделать как я сказал, то это займет минут 20 максимум.
--
Роман И. Кузьменко (http://clairbee.void.ru/) (mailto:kuz@pisem.net)
Re[5]: Разделение одного реального соединения на несколько
От: Sashko Россия http://www.dc.baika.ru/
Дата: 10.06.03 04:34
Оценка:
"Fedorchenko Aleksey" <forum@rsdn.ru> wrote in message news:291599@news.rsdn.ru...
> 2 меньших расходах на управление сокетами (сейчас для каждого соединения создается свой
> поток, но при этом загруженность его составляет менее 5%, т.к. время обработки данных куда
> больше времени передачи результирующих данных)

На каждое сокетное соединение создавать новый thread — это конечно расточительство. Странно,

почему одного было не достаточно (ну либо конечного числа, если хочется иметь разный priority

у thread'ов). Это были мысли в сторону.



Ну а с одним сокетным соединением, Вы конечно ни куда не денетесь от описанной проблемы,

когда один из модулей не успевает обрабатывать данные идущие к нему, в результате видны 2а

варианта. 1ый — раздувать очередь не обработанных данных этого модуля (до каких-то размеров,

ну а после, остановка работы). 2ой, более логичный, переставать вычитывать данные, как

следствие, если где-то идет пакет другому модулю, он будет ждать пока затормозивший модуль

разгребет свою очередь. Все зависти от ситуации, на сколько это критично в Вашей системе.

В некоторых случаях это _очень_ критично, и тогда одним сокетрым соединением не обойтись.
Posted via RSDN NNTP Server 1.5
Re[2]: Разделение одного реального соединения на несколько
От: Fedorchenko Aleksey Украина  
Дата: 10.06.03 10:19
Оценка:
Здравствуйте, clairbee, Вы писали:

C>Рекомендуемая схема работы:


Что то я совсем не понял при чем здесь pipe
На случай межпроцессного взаимодействия?
Re[3]: Разделение одного реального соединения на несколько
От: clairbee Россия http://clairbee.void.ru/
Дата: 11.06.03 00:03
Оценка:
Здравствуйте, Fedorchenko Aleksey, Вы писали:

FA>Здравствуйте, clairbee, Вы писали:


C>>Рекомендуемая схема работы:


FA>Что то я совсем не понял при чем здесь pipe :)

FA>На случай межпроцессного взаимодействия?
На случай (ИМХО наиболее вероятный) если ты захочешь иметь возможность заблочиться в клиенте на получение данных, и не заморачиваться по поводу буфера, где хранить данные.
--
Роман И. Кузьменко (http://clairbee.void.ru/) (mailto:kuz@pisem.net)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.