Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.06.20;
Скачать: CL | DM;

Вниз

TServerSocket, TClientSocket. Синхронный и асинхронный, блокирующ   Найти похожие ветки 

 
Анонимщик ©   (2004-04-22 11:33) [0]

Синхронный и асинхронный, блокирующий и неблокирующий.

Что в контектсе сокетов значит "Синхронный и асинхронный, блокирующий и неблокирующий"?
Я почему-то думал, что синхронный режим - тот, что позволяет обеим сторонам общаться,
синхронизируя посылку данных друг другу. Т.е. работа в синхронном режиме подразумевает
некий диалог между ними.
Но вот читаю: "Асинхронными они названы по той причине, что их выполнение связано с
определенным диалогом и ни начало, ни завершение не ограничено какими-либо временными
рамками". Т.е. с точностью до наоборот. Почему так, можно спросить?

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

одна из сторон на время своего посылания данных блокирует другую?
И еще одно. Если режим асинхронный, то тогда нужно выставить тип для сервера - ctThreadBlocking,
а для клиента - ctBlocking? Тогда сервер для каждого клиентского соединения создает поток,
который с этим клиентом и работает. И вот мне не понятно, почему того же нельзя сделать
и для синхронного режима в принципе, т.е. почему нет этой возмодности.

Короче, я все напутал, прошу помочь распутать.

И последнее. Можно ли создавать TClientSocket не в главном потоке? Прочитал, что операционная
система сообщает о событиях для сокета в то окно, с контекстом потока которого сокет связан.
Естественно, в дочернем потоке никакого окна нет. Так дойдет ли куда-нибудь сообщение вообще?
Впрочем, так я уже делал, но, кроме этого, создавал еще и поток, который занимается обработкой
принимаемых/отправляемых данных для этого сокета. И данные приходят и отправляются. Но смутные
сомнения терзают все равно.

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


 
Digitman ©   (2004-04-22 12:06) [1]

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

понятия "блокирующий" и "неблокирующий" относится прежде всего к вызовам ф-ций и процедур в текущем кодовом потоке

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

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

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

вот ты звонишь, делаешь заказ и оговариваешь условия доставки и извещения :

1) я буду ждать посыльного с пиццей у дверей подъезда, сколько бы времени это ни заняло

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

2) я буду ждать ответного звонка с извещением о том, что посыльный УЖЕ стоит у моего подъезда с заказом (либо произошел некий глобальный катаклизм, и заказ получить не могу)

это - "неблокирующий" режим, ты не торчишь как идиот у дверей своего подъезда, а волен заниматься какими-то иными своими делами; как только тебе позвонят, это и будет фактом подтверждения фактической доставки либо отказ по причине катаклизма.. все что остается - отложить на секунду свои дела, спуститься к дверям подъезда и получить заказ, если он действительно доставлен

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

то же самое - с ф-циями и процедурами ядра и его подсистем (winsock - не исключение) : некоторые п/программы ("конторы") предоставляют оба механизма, некоторые предоставляют только один из них


 
Анонимщик ©   (2004-04-22 12:48) [2]

Спасибо, Digitman. Почти не сомневался, что ответишь именно ты. С этим прояснилось.
А как насчет синхронности/асинхронности и прочих вопросов?


 
Digitman ©   (2004-04-22 13:00) [3]

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

в режиме же неблокирующих вызовов может использовать, а можно и не использовать асинхронную нотификацию (извещения) об интересующих тебя произошедших по факту событиях

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


 
Анонимщик ©   (2004-04-22 13:43) [4]

Спасибо.
Теперь про TClientSocket и обоаботке сообщений.


 
Polevi ©   (2004-04-22 13:51) [5]

TClientSocket создает окно
тебе нужно написать цикл выборки сообщений из очереди дополнительного потока
while GetMessage(msg,0,0,0) do DispatchMessage(msg)


 
Digitman ©   (2004-04-22 14:05) [6]


> Можно ли создавать TClientSocket не в главном потоке?


можно.. в любом потоке, в котором тебе заблагорассудится


> Прочитал, что операционная
> система сообщает о событиях для сокета в то окно, с контекстом
> потока которого сокет связан.


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

но если речь идет о сокете как объекте класса TServer/ClientSocket, инициализируемом для работы в режиме non-blocking, то в этом режиме по-умолчанию задействуется механизм асинхронных нотификаций с посылкой сообщений окну, создаваемому автоматически при вызове Open ... тот поток, который вызвал Open, и будет "владеть" окном и монопольными правами/обязанностями по ожиданию/выборке/диспетчеризации оконных сообщений


 
Анонимщик ©   (2004-04-22 14:31) [7]

Значит, я ошибался, когда считал, что, если выставить тип сервера в stThreadBlocking, то тогда отправка сообщений будет происходить без промедления (в смысле, функция якобы тут же отрабатывает).
Но если поставить nonBlocking, то тогда обработка будет происходить только в одном потоке сервера. Так? А это очень неудобно. Хотелось бы с каждым клиентом иметь свой поток.


 
Digitman ©   (2004-04-22 14:47) [8]


> обработка будет происходить только в одном потоке сервера


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

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


 
Анонимщик ©   (2004-04-22 14:52) [9]

А чем же тогда stThreadBlocking и stNonBlocking отличаются вообще?
Кроме того, каким образом эту асинхронность включить, извиняюсь на назойливость.


 
Polevi ©   (2004-04-22 14:53) [10]

>Анонимщик ©   (22.04.04 14:52) [9]
F1 WSAAsyncSelect


 
Digitman ©   (2004-04-22 15:06) [11]

stNonBlocking не создает доп.потоков, но создает единственное окно (для приема нотификаций от своих гнезд, ассоциированных с активными клиентами) и устанавливает режим асинхр.нотификации вызовом WSAAsyncSelect

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


 
Digitman ©   (2004-04-22 15:12) [12]

при stThreadBlocking перевести гнездо в неблок.режим можно двумя способами :

1) в режим оконных нотификаций - вызовом WSAAsyncSelect, при этом придется "ручками" создать окно (ибо оно по умолчанию в stThreadBlocking не создается) и только после этого связать хэндл окна с хэндлом гнезда вышеупомянутой ф-цией

2) в режим событийных нотификаций - вызовом WSAEventSelect, при этом придется "ручками" создать объект Event и только после этого связать хэндл объекта Event с хэндлом гнезда вышеупомянутой ф-цией

далее, в зависимости от 1 или 2, в доп.потоке организуется либо цикл ожидания/выборки/диспетчеризации оконных сообщений либо цикл ожидания сигналов объекта Event


 
Анонимщик ©   (2004-04-22 15:30) [13]

Во, за это спасибо, буду пытаться.


 
Yermek   (2004-04-22 20:53) [14]

А можно такой вопрос:

Обязательно ли, если на ServerSocket ServerType=stThreadBlocking то и в ClientSocket обязательно должно быть NonBlocking.


 
Polevi ©   (2004-04-22 21:29) [15]

> [14] Yermek   (22.04.04 20:53)
нет


 
Yermek   (2004-04-22 21:46) [16]

"Краткость сестра таланта"

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


 
Fantasist ©   (2004-04-23 01:39) [17]


> Digitman ©   (22.04.04 12:06) [1]


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

1. Блокирующий. Ты открываешь почтового клиента, и ничего не делаешь, пока в нем не появиться новое письмо. После этого ты его читаешь и начинаешь что-то делать.

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

 Хочу сказать, что объяснения приеведенные в это треде весьма запутывающе. Думаю как раз из-за того, что объясняются следствия (работа TClietSocket/TServerSocket и их опции), а не факты их порождающие (WinSocket API). Я бы реккомендовал поизучать работу с сокетами непосредственно на уровне API, тогда станет понятно, что за "асинхронный режим работы", и что делает stThreadBlocking и stNonBlocking. А так же может выясниться, что TClietSocket/TServerSocket вовсе и не нужны. Со мной во всяком случае так и произошло на серверной части. Оказалось, что мне  удобнее и надежнее написать собственную реализацию класса серверного сокета используя API, нежели использовать готовую от Delphi.


 
Polevi ©   (2004-04-23 07:59) [18]

>Yermek   (22.04.04 21:46) [16]
отдельный поток для асинхронного режима как раз не обязателен для каждого нового клиента. достаточно одного кодового потока, который будет принимать уведомления от winsock о неких событиях (получение данных, акцепт клиента, дисконнект) и чтото делать. главное чтобы эти действия занимали как можно меньше времени, чтобы не блокировать транспорт


 
Digitman ©   (2004-04-23 08:58) [19]


> Fantasist ©   (23.04.04 01:39) [17]


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


вникни в [3]
как раз об этом я там и сказал
в чем же расхождение ?


> объясняются следствия (работа TClietSocket/TServerSocket
> и их опции), а не факты их порождающие (WinSocket API).


а какая разница, WinSock API или не WinSock API ? оболочка (в виде упомянутых компонентов) или не оболочка ? Суть от этого не меняется. Есть просто некий вызов, он м.б. блокирующим, а может быть и неблокирующим - в зависимости от реализации алгоритмов вызываемого кода. Если внутренний алгоритм вызыв.п/программы предусматривает асинхронные нотификации (тем или иным образом), его можно использовать, а можно и не использовать, если задействован неблок.механизм вызываемого алгоритма.

в случае с оболочкой WinSock API в виде упомянутых компонентов все так же остается в силе

например, тот же вызов метода Open() в неблок.режиме практически немедленно вернет управление, создав перед этим (если требуется) окно, связав окно с гнездом и запустив механизм коннекта...

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


 
Yermek   (2004-04-23 16:24) [20]

Как корректно закрыть ServerSocket (stThreadBlocking) если к нкму подключены ClientSocket, при ServerSocket.Close пограмма зависает.


 
Digitman ©   (2004-04-23 16:48) [21]


> Yermek   (23.04.04 16:24) [20]


либо закрыть все активные соединения (в списке Connections) ,прежде чем делать ServerSocket.Close, либо изменить радикальным образом явно неверный алгоритм метода ClientExecute

в любом случае то что творится в ClientExecute
заслуживает детального рассмотрения


 
Ермак ©   (2004-04-23 18:44) [22]

Вообще рекомендую бросить работать с компонентами типа TSocket - это такой гемор! В Делфи7 Борланд вообще их переделала - по новой разбираться с ними - пустая трата времени. Есть WinSock API, все просто и понятно, я за полчаса с ним разобрался и начал работать. Можно создавать сколько хочешь потоков, хоть с окном, хоть без окна, хоть в сервисе - дело хозяйское, ты все полностью контролируешь и понимаешь. Особенно если поток создавать не тупым TThread, а через Create Thread. Короче, рекомендую WinSock API и вообще код, чистый от компонентов!

Вот хорошая статья: http://book.itep.ru/7/sock_71.htm


 
Verg ©   (2004-04-23 19:01) [23]


>  В Делфи7 Борланд вообще их переделала - по новой разбираться
> с ними - пустая трата времени.


Пере.. что? Куда переделала, какие именно "компоненты" переделала?
TSocket - это тип данных из модуля WinSock.pas. По-сути - integer.


 
Verg ©   (2004-04-23 19:04) [24]

type
 {$EXTERNALSYM u_char}
 u_char = Char;
 {$EXTERNALSYM u_short}
 u_short = Word;
 {$EXTERNALSYM u_int}
 u_int = Integer;  {$EXTERNALSYM u_long}
 u_long = Longint;

{ The new type to be used in all
 instances which refer to sockets. }
 {$EXTERNALSYM TSocket}
 TSocket = u_int;


"Гемор", говоришь...


 
Piter ©   (2004-04-23 23:06) [25]

А можно попутный вопрос? Зачем нужна директива $EXTERNALSYM ?


 
Rouse_ ©   (2004-04-23 23:08) [26]

Type Parameter
Syntax {$EXTERNALSYM identifier}

The EXTERNALSYM directive prevents the specified Pascal symbol from appearing in header files generated for C++Builder. If an overloaded routine is specified, all versions of the routine are excluded from the header file.


 
Piter ©   (2004-04-24 12:28) [27]

Справку я читать умею. Я не понял что написано


 
Yermek   (2004-04-24 17:21) [28]

У меня еще вопрос созрел:

...
 Private
   sss:array[1..100] og string;
 Public
   ...

type
 EServerThread = class( Exception );
 TServerThread = class( TServerClientThread )
 private
   fSocketStream : TWinSocketStream;
 public
   procedure ClientExecute; override;
 end;

procedure My_procedure;
begin
...
end;

procedure TServerThread.ClientExecute;
begin
 ...
 My_procedure;
 sss[i]:=text;
 ...
end;


Вопрос: процедура ClientExecute будет вызывать процедуру My_procedure как только придет какое либо сообщение от клиента, невылезет ли ошибка при попытке обращения к ней, если клиентов подцепилось несколько одновременно и то же самое про переменные в Private или в Public


 
Polevi ©   (2004-04-24 17:56) [29]

не вылезет, если не будешь в ней использовать глобальные переменные без синхронизации


 
Yermek   (2004-04-24 19:07) [30]

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


 
Polevi ©   (2004-04-24 19:11) [31]

напрмер использовать критические секции


 
Yermek   (2004-04-24 19:13) [32]

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


 
Polevi ©   (2004-04-24 19:22) [33]

cs:=TCritycalSection.Creaate;

..
 cs.Enter; //пытаемся зайти в секцию, если она занята другим потоком - засыпаем, пока секцмя не освободится
 try
  //здесь работаем с глобальной перменной монопольно
 finally
   cs.Leave; //освобожлдаем секцию  
 end;


 
Yermek   (2004-04-24 19:32) [34]

побробую, что получится напишу, все равно спасибо


 
Игорь Шевченко ©   (2004-04-24 21:16) [35]

Piter ©   (24.04.04 12:28)

А чего понимать ? С++ Builder генерирует .h файлы по паскалевским. Для  символов, отмеченных EXTERNALSYM уже сгенерированы .h файлы, как правило, корпорацией Майкрософт, чтобы не было конфликтов, символы не участвуют в генерации.


 
Piter ©   (2004-04-24 22:22) [36]

Игорь Шевченко (24.04.04 21:16) [35]
С++ Builder генерирует .h файлы по паскалевским


а я и не знал. Значит, C++ Builder поддерживает синтаксис OP?


 
Yermek   (2004-04-24 22:58) [37]

> Digitman ©   (23.04.04 16:48) [21]

> либо закрыть все активные соединения (в списке
> Connections) ,прежде чем делать ServerSocket.Close

все равно если клиент сам рызрывает связь, программа сервера все равно виснет, а если с клиента послать допустим SentText("close") а сервер обработает потом зактоет сам клиента то все нормально работает

а можно как нибуть почеловечески его закрыть.

> изменить радикальным образом явно неверный алгоритм метода
> ClientExecute

а вот этого я не понял... совсем...


 
Digitman ©   (2004-04-25 12:29) [38]


> Yermek   (24.04.04 22:58) [37]


я не телепат и догадываться, что у тебя там творится в теле My_procedure(), не намерен


 
Yermek   (2004-04-25 14:55) [39]

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


 
Digitman ©   (2004-04-25 15:01) [40]


> так чтоб при этом сервер не стал виснуть


"виснет"-то сервер отнюдь не по прихоти сил небесных, а из-за того, что у ты допустил ошибку в алгоритме ... и есть вполне обоснованные подозрения, что ошибка эта  - в теле My_procedure() или п/программ из него вызываемых ... а ты говоришь "это в принцепи неважно")

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



Страницы: 1 2 вся ветка

Текущий архив: 2004.06.20;
Скачать: CL | DM;

Наверх




Память: 0.6 MB
Время: 0.111 c
1-1086188846
Snipers
2004-06-02 19:07
2004.06.20
Наследование форм


1-1086595878
rosl
2004-06-07 12:11
2004.06.20
удалить файлы


1-1086257109
Сашка
2004-06-03 14:05
2004.06.20
Перехват сообщений из dll


3-1085732139
KADAN
2004-05-28 12:15
2004.06.20
PASSWORD() в MSSQL?


4-1084725139
andruxin
2004-05-16 20:32
2004.06.20
помогите с отловом WM_SYSCOMMAND