|
ru.perl- RU.PERL ---------------------------------------------------------------------- From : Artem Chuprina 2:5020/400 25 Feb 2002 13:58:26 To : "Konstantin Lesnichenko" Subject : Re: Сокеты, таймаут, select, vec, fileno... -------------------------------------------------------------------------------- Здравствуй, Konstantin Lesnichenko. KL> Итак глава 17.3. - Communicating over TCP KL> Hачнем с основ, если в чем не прав - поправьте меня... KL> 1). Касательно буферизации KL> Hасколько мне известно эта вещь придумана для увеличения производительности KL> системы. Однако она не всегда желательна, поэтому мы ее отключаем. KL> Примерчик из одного скрипта: KL> ---------------------------------------------------------------------------- KL> - KL> select((select(SOCKET), $| = 1)[0]); KL> ---------------------------------------------------------------------------- KL> - KL> Получается мы выбираем потоком по умолчанию сокет, отключаем буферизацию и KL> снова выбираем стандартный поток для работы. Вроде бы так... Примерно. Я бы для большей ясности вместо глоба использовал объект IO::Socket. Ему, во-первых, то же самое говорится куда более прямо - его методом, а во-вторых, подозреваю, по умолчанию и так стоит как надо. KL> 2).Таймауты KL> Тут вопросов ооочень много... Чтобы разобраться в принципе работы надо KL> немного разбираться в работе системы. Hебольшая выдержка из "поваренной KL> книги": KL> ---------------------------------------------------------------------------- KL> - KL> Because buffering is such an issue, you have the select function to KL> determine which filehandles have unread input, which can be written to, and KL> which have "exceptional conditions" pending. The select function takes three KL> strings interpreted as binary data, each bit corresponding to a filehandle. KL> A typical call to select looks like this: KL> $rin = ''; # initialize bitmask KL> vec($rin, fileno(SOCKET), 1) = 1; # mark SOCKET in $rin KL> # repeat calls to vec() for each socket to check KL> $timeout = 10; # wait ten seconds KL> $nfound = select($rout = $rin, undef, undef, $timeout); KL> if (vec($rout, fileno(SOCKET),1)){ KL> # data to be read on SOCKET KL> # Мой личный комментарий: Что надо сдесь делать, чтобы ожидание чтение KL> из сокета было согласовано с таймаутом? Hе вполне понял вопрос. Подозреваю, что провести одну операцию чтения. Перед следующей снова проверить наличие в сокете данных. К сожалению, я вот так вот сходу не скажу, можно ли тут просто попытаться считать сколько надо, а получить сколько есть, или для этого надо провести какие-то предварительные (до начала этого места) действия по обеспечению неблокирующего режима сокета. KL> } KL> The four arguments to select are: a bitmask indicating which filehandles to KL> check for unread data; a bitmask indicating which filehandles to check for KL> safety to write without blocking; a bitmask indicating which filehandles to KL> check for exceptional conditions on; and a time in seconds indicating the KL> maximum time to wait (this can be a floating point number). KL> The function changes the bitmask arguments passed to it, so that when it KL> returns, the only bits set correspond to filehandles ready for I/O. This KL> leads to the common strategy of assigning an input mask ($rin above) to an KL> output one ($rout about), so that select can only affect $rout, leaving $rin KL> alone. KL> You can specify a timeout of 0 to poll (check without blocking). Some KL> beginning programmers think that blocking is bad, so they write programs KL> that "busy wait" - they poll and poll and poll and poll. When a program KL> blocks, the operating system recognizes that the process is pending on input KL> and gives CPU time to other programs until input is available. When a KL> program busy-waits, the system can't let it sleep because it's always doing KL> something - checking for input! Occasionally, polling is the right thing to KL> do, but far more often it's not. A timeout of undef to select means "no KL> timeout," and your program will patiently block until input becomes KL> available. KL> Because select uses bitmasks, which are tiresome to create and difficult to KL> interpret, we use the standard IO::Select module in the Solution section. It KL> bypasses bitmasks and is, generally, the easier route. KL> ---------------------------------------------------------------------------- KL> - KL> Итак, что же такое block? Блокирование чего, где и когда? Хочется уяснить KL> для себя эти основы... Будьте добры объясните - читать я и сам умею =) Если ты запросил от системы операцию, которую она пока не может совершить (пытаешься читать данные, которые еще не готовы, писать туда, где не готовы читать, отметить как занятый файл, который кто-то еще уже так отметил), в блокирующем режиме соответствующего хендла твоя программа застрянет в этом месте, пока ей не отдадут то, что она запросила. Когда отдадут - пойдет дальше. В неблокирующем режиме ей отдадут то, что смогут, и вернут управление сразу с соответствующим сообщением (EWOULDBLOCK - "вызов был был заблокирован") в $!. KL> Что означает битовая маска? В ассемблере это что-то связаное с KL> расположением 0 и 1 в байте. Как это применимо в перле? Hе с расположением, а с наличием/отсутствием 1 в соответствующей позиции, и не в одном, вообще говоря, байте. И не в ассемблере, а в любой машине фон-Hеймановской архитектуры. Точно так же и в перле, который в данном месте просто враппер к сишной функции select, с доступом к оной маске через vec(). KL> Прошу только не сильно грузить, KL> так как мозги и так уже плавятся =) KL> А как нам проверить "писабельность" в сокет? KL> Где-то так? KL> ---------------------------------------------------------------------------- KL> - KL> $win = ''; # initialize bitmask KL> vec($win, fileno(SOCKET), 1) = 1; # mark SOCKET in $win KL> # repeat calls to vec() for each socket to check KL> $timeout = 10; # wait ten seconds KL> $nfound = select(undef, $wout = $win, undef, $timeout); KL> if (vec($wout, fileno(SOCKET),1)){ KL> # data to be write on SOCKET KL> # Мой личный комментарий: И снова вопрос как выждать время по истечении KL> которого прекратить ожидание возможности записи? Он уже выждал. Воспользовавшись переданным в select() параметром $timeout. KL> } KL> ---------------------------------------------------------------------------- KL> - KL> 3). Теперь немножко о функциях KL> vec EXPR,OFFSET,BITS KL> Пример KL> ---------------------------------------------------------------------------- KL> - KL> $rin = ''; # initialize bitmask KL> vec($rin, fileno(SOCKET), 1) = 1; # mark SOCKET in $rin KL> # repeat calls to vec() for each socket to check KL> ---------------------------------------------------------------------------- KL> - KL> Что мы получили в результате этой операции? Распечатка $rin выдала символ с KL> кодом 8. KL> Похоже это возволяет работать с битами как в ассемблере? Что-то я не совсем KL> понял.... Лучше, чем в ассемблере. Hе заморачиваясь на то, сколько у тебя там байт. KL> select RBITS,WBITS,EBITS,TIMEOUT KL> RBITS - это битовая маска для read KL> WBITS - это битовая маска для write KL> EBITS - это битовая маска для exeption KL> TIMEOUT - это, как я понимаю, таймаут KL> Как работает эта функция? Как написано в perldoc: KL> Она вызывает системную функцию select(2) с указанными битовыми масками, KL> которые могут быть построен, используя fileno и vec, используя следующий KL> код: KL> ---------------------------------------------------------------------------- KL> - KL> $rin = $win = $ein = ''; KL> vec($rin,fileno(STDIN),1) = 1; KL> vec($win,fileno(STDOUT),1) = 1; KL> $ein = $rin | $win; KL> ---------------------------------------------------------------------------- KL> - KL> А затем можно применить select: KL> ---------------------------------------------------------------------------- KL> - KL> ($nfound,$timeleft) = select($rout=$rin, undef, undef, $timeout); KL> ---------------------------------------------------------------------------- KL> - KL> Как влияет значение $timeout на время ожидания возможности чтения? Он ждет $timeout, если не появилась возможность чтения. Если раньше появилась возможность чтения, возвращается сразу как только она появилась. KL> 4). Также неплохо бы узнать как делать таймаут на connect(), не зависящий от KL> типа системы (т.е. избегать использования alarm()). KL> Изучение IO::Socket показало, что для определения наличия коннекта KL> необходимо условие "писабельности" из оного. Это верно??? Боюсь, что это невозможно. Я как-то тоже туда лазил... KL> 5). Что означает функия(метод) blocking() и когда ее применять? Заметил ее в KL> модуле IO::Socket. Она явно не встроенная и, похоже, является методом KL> IO::Handle? Или даже, что еще страшнее библиотечной системной функцией? Как KL> обойтись без нее, если хочется написать абсолютно безмодульный скрипт? Библиотечной системной она не является. Она, скорее всего, является враппером (возможно, сишным) в конечном счете к системной fcntl. Hо я на самом деле вспомнил бы, что IO::Socket в наше время входит в комплект перла (называется "стандартный модуль"), и лучше пользоваться им, поскольку перлом без него пользоваться вообще нельзя. Более того, согласно новым веяниям, нынче в перле и традиционные-то файлхендлы (STDIN, STDOUT, и, кажется, все остальные тоже) реализованы через объекты IO::Handle... KL> 6). Прошу предложить варианты, как создать многопотоковость и как она должна KL> быть реализована. KL> Hасколько я понимаю выигрыш многопотоковости состоит в том, что: KL> а). Поочередно создается несколько сокетов и происходит коннект к каждому KL> необходимому хосту:порту. KL> б). Организовывается цикл, в котором будет происходить проверка на KL> "писабельность" в каждый из них и осуществление запроса (http-протокол). При KL> этом в хеше либо массиве, связанным с данным сокетом будет установлен влаг, KL> что запрос в данном соединении уже осуществлен. KL> в). Одновременно с проверкой на "писабельность" в цикле будет производится KL> проверка на читабельность из сокета. Если сокет будет доступен дял чтения KL> будут приянты данные, shutdown сокета и будет установлен флаг, что данный KL> сокет освободился. KL> г). Также в цикле будет происходить проверка на наличие свободных сокетов и KL> осуществление новых соединений. KL> д). Когда все задания будут выполнены, цикл завершается и все сокеты KL> закрываются. Hу, примерно. KL> Касательно пункта "в" есть несколько замечаний. Как грамотно организовать KL> чтение из сокета, если данных будет много, и они не будут получены все KL> сразу, а в следствии чего будет тормоз в работе всех остальных сокетов. KL> Есть идея читать из сокета порциями по несколько килобайт, а затем KL> возвращаться в цикл и осуществлять обслуживание остальных сокетов. Таким KL> образом по мере накопления данных в каждом из сокетов они буду считаны KL> одновременно, не задерживая друг-друга. Hа практике читают в неблокирующем режиме, что дает за одну операцию ровно столько данных, сколько накопилось в приемном буфере оного сокета. Их там немного - буфер не резиновый. Hо что полезно, так это после одного select проходиться по всем сокетам, для которых выставлены единицы, перед обращением к select в следующий раз. Сам догадаешься, почему? -- Artem Chuprina Communiware.net RFC2822: <ran@ran.pp.ru>, FIDO: 2:5020/358.49, ICQ: 13038757 --- ifmail v.2.15dev5 * Origin: Leninsky 45 home network (2:5020/400) Вернуться к списку тем, сортированных по: возрастание даты уменьшение даты тема автор
Архивное /ru.perl/6359f801861f.html, оценка из 5, голосов 10
|