Форум: "Сети";
Текущий архив: 2004.06.20;
Скачать: [xml.tar.bz2];
Вниз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;
Скачать: [xml.tar.bz2];
Память: 0.59 MB
Время: 0.035 c