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

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

Логика работы сокетов [D7, Win95/98, WinME, NT4, Win2k, WinXP]


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

_Sergey_ ©   (2006-09-05 22:57:00) 

Здравствуйте.
Недавно занялся сетевым программированием с использованием библиотеки WinSock (без применения каких-либо компонентов). Основная задача: написать сервер, который допускал бы подключение только одного клиента. Использую блокирующие сокеты, 1 поток и ф-ию select перед recv для осуществления отключения клиента от сервера по тайм-ауту передачи, клиент и сервер - консольные приложения. При этом возникли некоторые, как я полагаю, логические противоречия в работе сокетов.
1. перевожу сервер в режим ожидания подключения ф-ией listen, жду подключения от клиента, после подключения вызываю ф-ию accept. На этом этапе уже существуют 3 сокета:
1) клиентский
2) связанный с ним серверный
3) серверный в режиме ожидания подключения
Вызываю accept для 1-го клиента. После этого получаю данные от 1-го клиента. Но при этом подключаюсь к серверу 2-ым клиентом. Ф-ия connect 2-го клиента завершается без ошибки (2-й клиент добавляется в очередь на подключение). Самым "обидным" является то, что 2-ой клиент продолжает передавать данные, при этом ошибки send у него не появляется, т.е., он передает данные, которые уходят "в никуда". Вопрос: почему send отсылает данные без возникновения ошибок?
2. В обход сложившейся ситуации поступаю следующим образом: после подключения 1-го клиента вызываю CloseSocket для слушающего сокета сервера. При этом 1-й клиент передает данные без проблем (так и должно быть). Но возникает другая проблема: у 2-го клиента удачно завершается ф-ия connect (к какому слушающему сокету он подключается?). Но при первой же попытке передачи данных серверу 2-м клиентом возникает ошибка send. После этой ошибки клиент уничтожает свой сокет и переподключается. Сервер же после отключения 1-го клиента создает заново слушающий сокет и ожидает подключения. Вопрос: почему ф-ия connect 2-го клиента не завершается по ошибке (слушающий сокет на стороне сервера разрушен же)?

Изучал RFC793, RFC791, RFC768. Ситуация не прояснилась. Есть предположение, что для UDP и TCP-сокетов создаются одни и те же программные структуры (сокеты). Кроме того, есть предположение, возникшее после прочтения спецификаций, что слушающий сокет отличается от обычного только установкой спецфлага, т.е., имеет вх. и вых. буферы, и обмен информацией даже со слушающим сокетом не запрещен. И так, как в UDP реализуется передача данных до установления соединения, то реализуется ситуация 1 (данные записываются во вх. буфер слушающего сокета, ошибка не возникает). 2-я ситуация: ф-ия connect проверяет только наличие сокета, но не проверяет, слушающий он или нет. Поправьте меня, если я ошибаюсь.
Я задавал подобный вопрос на одном из форумов: http://www.delphikingdom.com/asp/answer.asp?IDAnswer=44294
Ответа на свой вопрос я, к сожалению, не получил. Буду рад любой информации: ссылки на документацию, адреса специализированных форумов, на кот. я могу получить ответы на мои вопросы.


_Sergey_   (2006-09-13 11:41:00) [21]


> в этом

Это не ограниченность, а реальность.


> я имел ввиду реализацию полностью однопоточного сервера
> без дисконнектов

Правильно. У меня сейчас полностью однопоточный сервер без дисконнектов. Сервер не создает канал обмена данными, пока он обслуживает хотя бы 1-го клиента (для 2-го клиента просто не вызывается accept). И дисконнект он не вызывает для 2-го (N-го) клиента. 2-ой клиент добавляется в очередь на подключение, но поскольку он не получает от сервера разрешения на передачу, то он определяет, что он не первый. И повторяет попытку подключения.


> повышают, установка TCP соединения - сравнительно затратный
> процесс.

Вот как раз на сервер нагрузку и не повышают. Соединение то не устанавливается.


> 1.именно так и нужно делать сразу. по крайней мере, мне
> не понятны причины, почему так не делать.

Потому, что и 1 потока мне достаточно. Незачем создавать лишние потоки, если теоретическая производительность, расчитанная на основании теста, превышает ожидаемую более чем в 800 раз.


> 2. почему именно на блокирующих?

Идеология их мне понравилась. Простота (линейность пргграммы). Да и незачем мне вызывать сетевые ф-ии, чтобы они выполнялись в фоне. Я должен быть уверен, что ф-ия завершилась с каким-то результатом к моменту, когда программа собирается выполнить след. ф-ию или операцию. Тем более, в *NIX системах "родными" являются блокирующие сокеты. Если будет задача перенести все это на сервер, работающий под *NIX, то проблемы почти минимальны - все ф-ии для работы с сетью у меня только стандартные, не используются Windows-расширения. Останется только переписать некоторый дополнительный код, попробывать скомпилировать Kylix или FreePascal (говорят, неплохая совместимость с Delphi). На худой конец, не составит большого труда перевести на C++ под gcc. Но тут уже придется постараться (для меня).


> собственное умозаключение?

Не совсем. "Размножать" и уничтожать потоки - это довольно ресурсоемкий процесс. Поэтому в 1 поток обычно выносится работа с несколькими клиентами. А у меня будет 1 поток = 1 клиент.

"Какой вариант использовать - поток на каждый сокет, либо один поток обрабатывает все соединения - вопрос, к которому нужно подходить по-разному в каждом конкретном случае. Если в процессе общения с клиентом серверу требуется значительное время на подготовку и обработку данных, то, конечно, следует создать разные потоки, чтобы другим клиентам не пришлось ожидать завершения обработки, а работать паралелльно. В противном случае, если обработка минимальна, то создание большого количества процессов окажет влияние в худшую сторону на общую производительность системы." (c)

Теперь у меня есть 1 поток - "кусочек" многопоточного сервера, и мой сервер всегда можно переделать в многопоточный.

Остался вопрос по SetThreadAffinityMask. Если имеется многопоточный сервер, то:
1) Если NT, то определить кол-во установленных процессоров через GetSystemInfo.
2) Для каждого подкл. клиента создавать свой поток, привязывая его SetThreadAffinityMask сначала к 0, след. поток - к 1-му, ... N, затем снова 0-му процессору?


> Подозреваю, что ты изначально пошер неверной дорогой.
>
> Если речь идет только об ЛВС под управлением Windows, то
> задача ...

Почему только под управлением Windows?
http://en.wikipedia.org/wiki/Named_pipe
Pipes - это идеология изначально *NIX-систем, в кот. они используются для коммуникации между процессами.
http://www.kolasc.net.ru/cdo/programmes/os/343.htm

Для того, чтобы связать процессы на разных ПК, нужно создать Named Pipes.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ipc/base/named_pipes.asp
"Windows Me/98/95:  Named pipes cannot be created." (с)
Поэтому этот вариант не подходит.


Сергей М.   (2006-09-13 08:44:00) [22]


> _Sergey_


Подозреваю, что ты изначально пошер неверной дорогой.

Если речь идет толькооб ЛВС под управлением Windows, то задача "гарантия доставки + минимизации сетевой нагрузки + максимальная производительность транспорта + ограничение числа одновременно обслуживаемых сервером клиентов" с легкостью решается использованием именованых программных каналов (вместо Winsock).


Eraser   (2006-09-13 01:43:00) [23]

> [62] _Sergey_ ©   (12.09.06 22:11)


> Максимум - 10. Вопрос: в чем ограниченность моего мышления?

в этом

> Такое число клиентов не планируется, и его не будет никогда!


> Реконнекты клиентов не повышают нагрузку на сервер.

повышают, установка TCP соединения - сравнительно затратный процесс.

> Уже реализовал. Благодаря твоей же
> подсказке. Как я сразу сам не додумался ввести обратную
> связь перед передачей, ума не приложу.

хм.. а при чем тут обратная связь.. я имел ввиду реализацию полностью однопоточного сервера без дисконнектов, о которых писали тут [59].

> На около 2000 передач от клиентов у меня было 20-50 повторных
> передач из-за занятости сервера.

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

> Если еще не убедил, то скажу так. Win 9x плохо переносят
> многопоточные приложения

угу, когда создешь около десятка загруженных потоков - плохо )

> в частности, сетевые многопоточные приложения, прекрасно
> работающие на WinNT, работают и на Win 9x, но периодически
> "вылетают" с разными сообщениями об ошибках

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

> Для меня важна совместимость, начиная по крайней мере с
> W98.
> Понятно, что достаточно хотя бы 1 машинки под WinNT, и можно
> подумать и о
> conditional acceptance, и об других, специфичных для WinNT
> 4.0+ WinSock 2.2 Windows-расширениях ф-ий работы с сокетами.

вот то-то и оно, кстати, если уж на то пошло - есть повод задуматься о разных версиях реаизации протокола для разных систем.. реализовать это не так уж сложно.

> Если все же производительности сервера мне не будет хватать-
> >если повторных передач будет слишком много->если клиенты
> будут простаивать долго, то я сделаю так:
> вынесу код работы с клиентом (после accept) в отдельную
> процедуру, защищу код обработки пакетов критической секцией,
> и буду создавать отдельные потоки на каждое соединение,
> но ограничу максимальное число потоков, скажем, 30-ю. Таким
> образом, у меня получится многоклиентский сервер на блокирующих
> сокетах

1.именно так и нужно делать сразу. по крайней мере, мне не понятны причины, почему так не делать.
2. почему именно на блокирующих?
3. все уже сделано до тебя, называется TIdTCPServer :)

> не самая удачная реализация, но ее будет довольно

тоже не понятно почему? собственное умозаключение?

> но при зависании хотя бы 1 потока в этом случае и не выхода
> из критической секции все ост. потоки будут блокированы.

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

PS и все таки еще раз посоветую - не изобретай велосипеды, на своем опыте не раз убеждался - неблагодарное это занятие :)


_Sergey_   (2006-09-12 22:11:00) [24]


> зачем ограничивать количество соединений

Все начинается с малого. Пример: 100 кг груз можно перевести легковой машиной и грузовиком. Но 20 т легковой машиной не перевезти. Когда мне понадобится перевезти 20 т, я возьму грузовик: по моим расчетам мой сервер (теоретически, на основе подсчета числа обслуженных клиентов при стресс-тесте) уже, при одноклиентской реализации,сможет обслужить около 20 тыс. клиентов за примерно 30 мин. на P4. Это идеальные условия. Сбросим 3 тыс. на перепередачу при занятости сервера. И того: 17 тыс. за 30 мин. в ЛС. А если учесть, что каждый из клиентов будет передавать небольшой пакет через примерно 15 мин., получится, что половина из 17 тыс. - это и есть число работающих клиентов (отдельных машин, или задействованных процессоров при использовании многопроцессорных машин [на них запускается столько клиентов, сколько на них установлено процессоров]). И того получается оч. большая цифра: 8 500 клиентов. Такое число клиентов не планируется, и его не будет никогда! Максимум - 10. Вопрос: в чем ограниченность моего мышления? Если и так запас по производительности по теоретическим оценкам превосходит ожидаемое число клиентов в 850 раз. Все просто.


> это "решение" уменьшает производительность системы

Реконнекты клиентов не повышают нагрузку на сервер. Разве что в те несколько секунд реконнектов клиента загружают процессор, на котором работает клиент. И то я в клиенте использую при реконнекте sleep(2000), получается, я не столько загружаю процессор на клиентской стороне, сколько теряю процессорное время на стороне клиента. Но что такое пару секунд по сравнению с 15 минутами?
Тем более, даже в стресс-тесте реконнект клиентов в текущей реализации - единичные случаи. На около 2000 передач от клиентов у меня было 20-50 повторных передач из-за занятости сервера. Могу протестировать еще раз и выслать логи клиента на мыло, если интересно. Думаю, у мнея не самые плохо реализованные логи :) Причем, и серверные тоже могу выслать. Но там будет несколько Мб подобного текста, но все события довольно подробно описаны.

> увеличивает нагрузку на ... сеть

Работать приложение будет в ЛВС. Если и будут повторные передачи, то их будет оч. мало, судя по стресс-тесту. Скорость там достаточная, и небольшим количеством "лишних" маленьких пакетов можно пренебречь, как мне думается.


> трудно реализуемо

Уже реализовал. Благодаря твоей же
подсказке. Как я сразу сам не додумался ввести обратную связь перед передачей, ума не приложу.


> бесполезно

Если еще не убедил, то скажу так. Win 9x плохо переносят многопоточные приложения (заявление из собственного опыта и высказываний людей на разных форумах, в частности, сетевые многопоточные приложения, прекрасно работающие на WinNT, работают и на Win 9x, но периодически "вылетают" с разными сообщениями об ошибках. Это только один из примеров.). Для меня важна совместимость, начиная по крайней мере с W98.
Понятно, что достаточно хотя бы 1 машинки под WinNT, и можно подумать и о
conditional acceptance, и об других, специфичных для WinNT 4.0+ WinSock 2.2 Windows-расширениях ф-ий работы с сокетами. Но могу сказать так:
Если все же производительности сервера мне не будет хватать->если повторных передач будет слишком много->если клиенты будут простаивать долго, то я сделаю так:
вынесу код работы с клиентом (после accept) в отдельную процедуру, защищу код обработки пакетов критической секцией, и буду создавать отдельные потоки на каждое соединение, но ограничу максимальное число потоков, скажем, 30-ю. Таким образом, у меня получится многоклиентский сервер на блокирующих сокетах (не самая удачная реализация, но ее будет довольно). При этом уменьшится время реакции сервера (клиент почти гарантированно будет передавать пакеты сразу), но при зависании хотя бы 1 потока в этом случае и не выхода из критической секции все ост. потоки будут блокированы. Сервер при этом будет в нерабочем состоянии. Время реакции сервера уменьшится, но не увеличится скорость обработки пакетов, поскольку в моей реализации сейчас: если сервер не создает канал связи с очередным клиентом, значит, он в этот момент обрабатывает данные, пришедшие от предыдущего клиента, или принимает эти данные. А все эти процедуры оч. быстрые. Таким образом, выиграш в производительности ожидается мизерный (на основе информации, изложенной выше). Вопрос: а стоит ли гнаться за сомнительными меньше 1% приростами в задачах, когда этот прирост будет проявлять себя лишь при нагрузках, больших в 850 раз, чем планируемые нагрузки?


Eraser   (2006-09-12 17:16:00) [25]

> [60] _Sergey_ ©   (12.09.06 17:05)


> Сервер, работающий с 1 client max - это простое решение.

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


_Sergey_   (2006-09-12 17:05:00) [26]


> код сервера:

Ээх. Спасибо за пример, но назад я возвращаться не буду.


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

Может, действительно не в состоянии. Я могу это признать. Я любитель, а не профессионал. Тем более, занимаюсь программированием для сетей 3 месяца с перерывами. Сервер, работающий с 1 client max - это простое решение. И его с головой хватит для моей задачи. В жестких условиях тестирования он себя хорошо показал. В таких условиях, как при тесте, он небудет работать никогда. Тем не менее, и при тесте он справляется. Это не сервер, предназначенный для передачи файлов.

> см. TServerSocket.ActiveConnections

TServerSocket.Socket.ActiveConnections - число законнекченных клиентов
При его превышении я могу только вручную (через св-ва) отконнектить лишних. А это не годится. Лишние клиенты совсем не должны коннектиться.

> либо настоящий полноценный сервер, реализующий ...

Думаю, меня и текущая реализация вполне устраивает. Она имеет запас по производительности и надежность. Защита, правда, минимальна. Но, если мое приложение и будет использоваться, то только в изолированной ЛС, где никто не будет пытаться навредить его работе (подделывать пакеты для отправки, досить, ...). Мои вопросы по реализации безопасности - это вопросы на будущее. С уклоном: авось пригодится; а вдруг придется реализовывать. А пока меня больше волнуют вопросы обеспечения совместмости с HT. Буду пробовать использовать SetThreadAffinityMask
.


Сергей М.   (2006-09-12 08:56:00) [27]


> _Sergey_ ©   (12.09.06 00:17) [53]
> Это компоненты, создающие в неблок. режиме столько подключений,
>  сколько клиентов попытается подключиться. В блок. режиме
> - другое дело.


Дались тебе эти "лишние" подключения !)

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

И хоть в блокирующем хоть в неблокирующем режиме все это происходит - нет никакой разницы.


> А еще там св-во есть, MaxConnections называется. Оч. полезное
> св-во


Ничего полезного оно для тебя не представляет. Работатет оно точно так же примитивно - если очередной подключившийся клиент "лишний", для него тут же выполняется дисконнект.


> подскажете, как именно реализуется этот контроль?


см. TServerSocket.ActiveConnections


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


Вот и обрабатывай их правильно)..  в чем проблема-то ?

По поводу DoS-атак, если они так тебя волнуют, ты уж выбирай - либо настоящий полноценный сервер, реализующий true conditional acceptance, либо его жалкое примитивное подобие, опирающееся на backlog queue size = 1


Eraser   (2006-09-12 01:21:00) [28]

> [56] _Sergey_ ©   (12.09.06 00:51)


> К примеру, в idTCPServer поставлю MaxConnections=1.

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

> Что такое ICS?

компоненты, основанные на неблокирующих сокетах.

> Боюсь, назад дороги нет :)

код сервера:

unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, IdBaseComponent, IdComponent, IdCustomTCPServer, IdTCPServer,
 IdContext, IdGlobal;

type
 TfmMain = class(TForm)
   IdTCPServer1: TIdTCPServer;
   procedure IdTCPServer1Execute(AContext: TIdContext);
   procedure FormCreate(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 fmMain: TfmMain;
 csSync: RTL_CRITICAL_SECTION;

implementation

{$R *.dfm}

procedure TfmMain.FormCreate(Sender: TObject);
begin
 InitializeCriticalSection(csSync);
 IdTCPServer1.DefaultPort := 777;
 IdTCPServer1.Active := true;
end;

procedure TfmMain.IdTCPServer1Execute(AContext: TIdContext);
var
 Buf: TBytes;
 BufSize: Integer;
begin
 AContext.Connection.IOHandler.Write(Integer(1));
 AContext.Connection.IOHandler.ReadInteger; // Dummy value.
 try
   EnterCriticalSection(csSync);
   BufSize := AContext.Connection.IOHandler.ReadInteger; // Размер пакета.
   AContext.Connection.IOHandler.ReadBytes(Buf, BufSize); // Принимаем буффер.
 finally
   LeaveCriticalSection(csSync);
 end;
end;

end.

код клиента:

unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
 IdGlobal;

type
 TfmMain = class(TForm)
   procedure FormCreate(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 fmMain: TfmMain;

implementation

{$R *.dfm}

procedure TfmMain.FormCreate(Sender: TObject);
var
 IdTCPClient: TIdTCPClient;
 buf: TBytes;
begin
 SetLength(buf, 100);  // Устанавливаем длину пакета.
 buf[0] := 77; // Инициализируем пакет.
 IdTCPClient := TIdTCPClient.Create(Application);
 try
   IdTCPClient.Host := '127.0.0.1';
   IdTCPClient.Port := 777;
   IdTCPClient.Connect;
   IdTCPClient.IOHandler.ReadInteger;
   IdTCPClient.IOHandler.Write(Integer(1));
   IdTCPClient.IOHandler.Write(Integer(Length(buf))); // Отсылаем размер буффера.
   IdTCPClient.IOHandler.Write(buf); // Отсылаем буффер.
   IdTCPClient.Disconnect;
 finally
   IdTCPClient.Free;
 end;
end;

end.

пример на Indy 10, встроенного в BDS2006.


_Sergey_   (2006-09-12 00:53:00) [29]


> Rouse_ © [49]

Что такое ICS?


_Sergey_   (2006-09-12 00:51:00) [30]


> Eraser © [54]

Боюсь, назад дороги нет :)
Можно сказать, что сейчас я доволен реализацией и работой. Может, следует попытаться защитить и усложнить обработку, но на первых порах неплохо.


Eraser   (2006-09-12 00:36:00) [31]

> [53] _Sergey_ ©   (12.09.06 00:17)


> IdTCPServer - компонент, сетевая логика которого основана
> на блок. сокетах.

Эт я в курсе :)
его и советую использовать.


_Sergey_   (2006-09-12 00:36:00) [32]


> Есть такой контроль. Вполне успешно работающий.

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


> По-твоему, возникающие ошибки должны "замалчиваться" компонентами,
> так что ли ?

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


> Вот уж глупости. И причем здесь вообще Telnet ? Компоненты эти
> реализуют транспортный уровень, ни больше ни меньше. Прикладной же
> уровень в этом случае целиком и полностью на твоей совести.

Не вижу здесь глупости. Прикладной уровень то на моей совести. Но как я смогу отключить клиента, если я даже не знаю, что кто-то уже подключился к серверу. К примеру, в idTCPServer поставлю MaxConnections=1. Вызвать DOS для такого сервера проще не бывает - подключиться к нему телнетом. А тогда на совести, не на совести, а вся логика прикладного уровня не будет иметь никакого смысла, ведь сервер даже не будет знать, что единственный канал связи уже занят.


_Sergey_   (2006-09-12 00:17:00) [33]


> TServerSocket/TTCPServer в неблок.режиме как раз и реализуют
> однопоточный серверный транспорт.

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

IdTCPServer - компонент, сетевая логика которого основана на блок. сокетах. Вот к тому и упоминаю. А еще там св-во есть, MaxConnections называется. Оч. полезное св-во.


Eraser   (2006-09-11 16:06:00) [34]

> [50] _Sergey_ ©   (11.09.06 13:33)


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

ну тут уже не раз повторили, что это ерунда, то что та пишешь.

какие проблемы с крит. секцией? 2 строчки кода (ну пусть 5, с учетом try..finally..end) это проблемы?
а вот реализация полностью однопоточного сервера, в том виде, что ты хочешь - вот это проблема.

насчет компонентов - согласен с Сергеем М., в таких базовых компонентах как TServer/ClientSocket или TIdTCPServer я глюков не встречал, они имеются в более сложных реализациях, но в этих компонентах - вряд ли.

> при приеме данных ждет прихода хотя бы 1-го байта (причем,
> может ждать и 5 мин., и час, и два ...);

см. свойство ReadTimeout.

> понравилась инсталляция Indy 10 на D7 (инсталлятор даже
> не смог правильно подключить 10 версию, хотя он был специально
> предназначен для D7

опять же - просто надо уметь готовить :) у меня проблем с инсталляцией не возникало.

> P.S> Когда я скачал документацию с оф. сайта по Indy 10
> в *.html (запакованные), я ужаснулся. Если там код находится
> в таком же состоянии, как и документация, то я удивляюсь,
> как он вообще работает. Кто видел эту документацию, поймет
> меня.

не знаю как на сайте, их chm файл меня вполне устраивал, сейчас правда пользуюсь встроенной справкой из BDS2006.

> Т.е., SSL, или шифрование.

не обязательно. я имел ввиду свою реализацию, к примеру, на базе MS Crypto API, что не так уж и трудно.


Сергей М.   (2006-09-11 13:56:00) [35]


> последовательная обработка позволяет не "заморачиваться"
> с синхронизацией потоков, критическими секциями


Это никак не вяжется с изначальным вопросом.
Берешь обычные TServer/ClientSocket или TTCPServer/Client и используешь их в неблок.режиме - вот тебе и послед.обработка и гарантированная доставка сообщений.


> однопотоковый сервер в состоянии обслужить всех клиентов


TServerSocket/TTCPServer в неблок.режиме как раз и реализуют однопоточный серверный транспорт.
И не понятно, к чему ты при этом упомянул TIdTCPServer - он заведомо многопоточный.


_Sergey_   (2006-09-11 13:33:00) [36]


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


По специфике работы моего серверного приложения оно не требует реализации сервера в многоклиентском виде, поскольку нагрузка на сервер минимальна, и, если сервер не может обслужить очередного клиента, значит, он занят непродолжительной процедурой обслуживания какого-то клиента. В данном случае последовательная обработка позволяет не "заморачиваться" с синхронизацией потоков, критическими секциями, позволяет не обходить тупиковые ситуации (когда один процесс заблокировал какой-то ресурс), поскольку и однопотоковый сервер в состоянии обслужить всех клиентов.


Rouse_   (2006-09-11 13:31:00) [37]

Слушай, возьми ICS и не мучайся, давным давно Пиетта за нас все написал, ни убавить ни добавить (правда не весь функционал, но все-же) :)


Сергей М.   (2006-09-11 13:30:00) [38]


> 1) стандартные TClientSocket, TServerSocket. Много "глюков":
>  образование незакрытых соединений


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


> нет контроля над кол-вом создаваемых потоков (каналов связи)


Есть такой контроль. Вполне успешно работающий.


> выдают разные сообщения об ошибках в виде MessageBox-ов


По-твоему, возникающие ошибки должны "замалчиваться" компонентами, так что ли ?


> при подключении Telnet-ом не определяет, что к серверу кто-
> то подключился


Вот уж глупости. И причем здесь вообще Telnet ? Компоненты эти реализуют транспортный уровень, ни больше ни меньше. Прикладной же уровень в этом случае целиком и полностью на твоей совести.


> при приеме данных ждет прихода хотя бы 1-го байта (причем,
>  может ждать и 5 мин., и час, и два


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

В блокирующем же режиме никто не запрещает воспользоваться select'ом для работы с транспортом по таймаутам.


> И никак не баги разработчиков компонентов


Нет там никаких сколь-либо серьъезных "багов".
А если и есть - на то имеются исх.тексты.


_Sergey_   (2006-09-11 13:26:00) [39]


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


Т.е., SSL, или шифрование. На сегодняшний день нашел только 1 компонент, позволяющий шифровать данные, но он визуальный, и требует наличия формы. Я же хочу оставить свое приложение консольным. Сам написать модуль, обеспечивающий должный уровень шифрования, я не в силах. Готового не нашел. Могу реализовать что-то простенькое, что защитит только "от дурака".
Есть пример связывания Indy 9 (10) с библиотекой OpenSSL. Единственной библиотекой, как я понял, доступной для связывания с Delphi (с предварительной небольшой адаптацией). Но этот пример, как мне кажется, работает как-то "неправильно". В самом примере при переведении в активное состояние idTcpServer, связанного с OpenSSL, введена задержка по таймеру. Если эту задержку убрать, то возникают разного рода ошибки. Кроме того, при переведении этого же idTcpServer в неактивное состояние приложение с idTCPServer-ом "вываливается" по Access violation ... Чьи это проблемы - Indy или OpenSSL, я не знаю. Но проблемы налицо. Кроме того, я предполагаю, что будет не так-то просто связать консольное приложение на Delphi с OpenSSL, поскольку нужно написать некий промежуточный код, который позволил бы свести взаимодействие с библиотекой SSL к простому вызову процедур для открытия сертификата ... Есть еще вариант - 3 компонент. Но не хочу я использовать сторонние компоненты. Хотя, есть серьезные предположения, что как раз этот компонент реализован довольно "качественно". Что Вы можете посоветовать из числа готовых программных пакетов для применения с Delphi (консольное приложение) для шифрования или создания защищенных линий связи?


_Sergey_   (2006-09-11 13:09:00) [40]


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


В том-то и дело, что до того, как реализовывать сетевую логику работы на ф-иях библиотеки сокетов, я пробовал реализовать ее же с помощью различных компонентов:
1) стандартные TClientSocket, TServerSocket. Много "глюков": образование незакрытых соединений при активном тестировании, нет контроля над кол-вом создаваемых потоков (каналов связи), иногда выдают разные сообщения об ошибках в виде MessageBox-ов, при подключении Telnet-ом не определяет, что к серверу кто-то подключился, кроме того, при приеме данных ждет прихода хотя бы 1-го байта (причем, может ждать и 5 мин., и час, и два ...)...
2) Indy. Реализован полностью на блокирующих сокетах, даже есть св-во max числа подключений. Но: при подключении Telnet-ом не определяет, что к серверу кто-то подключился, кроме того, при приеме данных ждет прихода хотя бы 1-го байта (причем, может ждать и 5 мин., и час, и два ...); не понравилась инсталляция Indy 10 на D7 (инсталлятор даже не смог правильно подключить 10 версию, хотя он был специально предназначен для D7); не удалось отключать клиента внутри таймера, т.к. управление объектом, идентифицирующем соединение, реализуется только внутри процедуры обработки прихождения данных от клиента (название процедуры точно не помню), в Indy 10 была частично перестроена иерархия св-в для объектов и изменена сама иерархия объектов, что решило эту проблему ...
3) Пишу сейчас не из домашней машинки. Название не могу глянуть, но пробовал еще 1 пакет компонентов. Коммерческий продукт, реализации существуют для Borland C++ Builder, Borland Delphi и кажется, Kylix, для разных версий. Отдельно были компоненты, поддерживающие SSL. Но там не было св-ва, ограничивающего число подключений. Хотя, при подключении к такому серверному компоненту telnet-ом, он определил факт подключения, чего не смогли сделать компоненты, описанные в 1) и 2).

Поэтому решил написать сам. На более низком уровне, чем использование компонентов. Ниже - только работа с драйверами и написание своих драйверов. В такие дебри пускаться я не хочу. И теперь, мое приложение будет иметь баги MS (библиотека сокетов), Borland (компилятор), и мои. И никак не баги разработчиков компонентов. Кроме того, я могу настроить св-ва (адаптировать работу сокетов под свои нужды) и контролировать каждое соединение.

P.S> Когда я скачал документацию с оф. сайта по Indy 10 в *.html (запакованные), я ужаснулся. Если там код находится в таком же состоянии, как и документация, то я удивляюсь, как он вообще работает. Кто видел эту документацию, поймет меня.


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

Наверх

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