Книга «Введение в программирование трехмерных игр с DirectX 9.0» представляет собой введение в программирование интерактивной трехмерной компьютерной графики с использованием DirectX 9.0, в котором основное внимание уделяется разработке игр. Книга начинается с исследования необходимых математических инструментов и базовых концепций трехмерной графики. Другие темы охватывают как выполнение в Direct3D базовых операций, таких как рисование графических примитивов, освещение, наложение текстур, альфа-смешивание и работу с трафаретами, так и использование Direct3D для реализации техник, необходимых в играх. Главы посвященные вершинным и пиксельным шейдерам включают описание каркасов эффектов и нового высокоуровневого языка программирования шейдеров (HLSL).
Эта книга начинает с основ безопасности вашего компьютера, таких, как определение необходимости в средствах защиты и его текущего уровня защищенности. Далее в ней показывается и достаточно подробно объясняется, как усилить защищенность, выбрать высокоскоростное подключение к Интернету, установить средства защиты персонального компьютера и оценить новый уровень защищенности.
Книга дополнена материалами, отражающими специфику Интернета в России и в странах СНГ.
Данная статья предназначена для начинающих программистов, которые никогда не работали с потоками, и хотели бы узнать основы работы с ними. Желательно, чтоб читатель знал основы ООП и имел какой-нибудь опыт работы в Delphi.
Для начала давайте определимся, что под словом "поток" я подразумеваю именно Thread, который еще имеет название "нить". Нередко встречал на форумах мнения, что потоки не нужны вообще, любую программу можно написать так, что она будет замечательно работать и без них. Конечно, если не делать ничего серьёзней "Hello World" это так и есть, но если постепенно набирать опыт, рано или поздно любой начинающий программист упрётся в возможности "плоского" кода, возникнет необходимость распараллелить задачи. А некоторые задачи вообще нельзя реализовать без использования потоков, например работа с сокетами, COM-портом, длительное ожидание каких-либо событий, и т.д.
Всем известно, что Windows система многозадачная. Попросту говоря, это означает, что несколько программ могут работать одновременно под управлением ОС. Все мы открывали диспетчер задач и видели список процессов. Процесс - это экземпляр выполняемого приложения. На самом деле сам по себе он ничего не выполняет, он создаётся при запуске приложения, содержит в себе служебную информацию, через которую система с ним работает, так же ему выделяется необходимая память под код и данные. Для того, чтобы программа заработала, в нём создаётся поток. Любой процесс содержит в себе хотя бы один поток, и именно он отвечает за выполнение кода и получает на это процессорное время. Этим и достигается мнимая параллельность работы программ, или, как её еще называют, псевдопараллельность. Почему мнимая? Да потому, что реально процессор в каждый момент времени может выполнять только один участок кода. Windows раздаёт процессорное время всем потокам в системе по очереди, тем самым создаётся впечатление, что они работают одновременно. Реально работающие параллельно потоки могут быть только на машинах с двумя и более процессорами.
Для создания дополнительных потоков в Delphi существует базовый класс TThread, от него мы и будем наследоваться при реализации своих потоков. Для того, чтобы создать "скелет" нового класса, можно выбрать в меню File - New - Thread Object, Delphi создаст новый модуль с заготовкой этого класса. Я же для наглядности опишу его в модуле формы. Как видите, в этой заготовке добавлен один метод - Execute. Именно его нам и нужно переопределить, код внутри него и будет работать в отдельном потоке. И так, попробуем написать пример - запустим в потоке бесконечный цикл:
Запустите пример на выполнение и нажмите кнопку. Вроде ничего не происходит - форма не зависла, реагирует на перемещения. На самом деле это не так - откройте диспетчер задач и вы увидите, что процессор загружен по-полной. Сейчас в процессе вашего приложения работает два потока - один был создан изначально, при запуске приложения. Второй, который так грузит процессор - мы создали по нажатию кнопки. Итак, давайте разберём, что же означает код в Button1Click:
тут мы создали экземпляр класса TNewThread. Конструктор Create имеет всего один параметр - CreateSuspended типа boolean, который указывает, запустить новый поток сразу после создания (если false), или дождаться команды (если true).
свойство FreeOnTerminate определяет, что поток после выполнения автоматически завершится, объект будет уничтожен, и нам не придётся его уничтожать вручную. В нашем примере это не имеет значения, так как сам по себе он никогда не завершится, но понадобится в следующих примерах.
Свойство Priority, если вы еще не догадались из названия, устанавливает приоритет потока. Да да, каждый поток в системе имеет свой приоритет. Если процессорного времени не хватает, система начинает распределять его согласно приоритетам потоков. Свойство Priority может принимать следующие значения:
tpTimeCritical - критический
tpHighest - очень высокий
tpHigher - высокий
tpNormal - средний
tpLower - низкий
tpLowest - очень низкий
tpIdle - поток работает во время простоя системы
Ставить высокие приоритеты потокам не стоит, если этого не требует задача, так как это сильно нагружает систему.
Ну и собственно, запуск потока.
Думаю, теперь вам понятно, как создаются потоки. Заметьте, ничего сложного. Но не всё так просто. Казалось бы - пишем любой код внутри метода Execute и всё, а нет, потоки имеют одно неприятное свойство - они ничего не знают друг о друге. И что такого? - спросите вы. А вот что: допустим, вы пытаетесь из другого потока изменить свойство какого-нибудь компонента на форме. Как известно, VCL однопоточна, весь код внутри приложения выполняется последовательно. Допустим, в процессе работы изменились какие-то данные внутри классов VCL, система отбирает время у основного потока, передаёт по кругу остальным потокам и возвращает обратно, при этом выполнение кода продолжается с того места, где приостановилось. Если мы из своего потока что-то меняем, к примеру, на форме, задействуется много механизмов внутри VCL (напомню, выполнение основного потока пока "приостановлено"), соответственно за это время успеют измениться какие-либо данные. И тут вдруг время снова отдаётся основному потоку, он спокойно продолжает своё выполнение, но данные уже изменены! К чему это может привести - предугадать нельзя. Вы можете проверить это тысячу раз, и ничего не произойдёт, а на тысяча первый программа рухнет. И это относится не только к взаимодействию дополнительных потоков с главным, но и к взаимодействию потоков между собой. Писать такие ненадёжные программы конечно нельзя.
Синхронизации потоков
Если вы создали шаблон класса автоматически, то, наверное, заметили комментарий, который дружелюбная Delphi поместила в новый модуль. Он гласит: "Methods and properties of objects in visual components can only be used in a method called using Synchronize". Это значит, что обращение к визуальным компонентам возможно только путём вызова процедуры Synchronize. Давайте рассмотрим пример, но теперь наш поток не будет разогревать процессор впустую, а будет делать что-нибудь полезное, к примеру, прокручивать ProgressBar на форме. В качестве параметра в процедуру Synchronize передаётся метод нашего потока, но сам он передаётся без параметров. Параметры можно передать, добавив поля нужного типа в описание нашего класса. У нас будет одно поле - тот самый прогресс:
Вот теперь ProgressBar двигается, и это вполне безопасно. А безопасно вот почему: процедура Synchronize на время приостанавливает выполнение нашего потока, и передаёт управление главному потоку, т.е. SetProgress выполняется в главном потоке. Это нужно запомнить, потому что некоторые допускают ошибки, выполняя внутри Synchronize длительную работу, при этом, что очевидно, форма зависает на длительное время. Поэтому используйте Synchronize для вывода информации - то самое двигание прогресса, обновления заголовков компонентов и т.д.
Вы наверное заметили, что внутри цикла мы используем процедуру Sleep. В однопоточном приложении Sleep используется редко, а вот в потоках его использовать очень удобно. Пример - бесконечный цикл, пока не выполнится какое-нибудь условие. Если не вставить туда Sleep мы будем просто нагружать систему бесполезной работой.
Надеюсь, вы поняли как работает Synchronize. Но есть еще один довольно удобный способ передать информацию форме - посылка сообщения. Давайте рассмотрим и его. Для этого объявим константу:
В объявление класса формы добавим новый метод, а затем и его реализацию:
Используя функцию SendMessage, мы посылаем окну приложения сообщение, один из параметров которого содержит нужный нам прогресс. Сообщение становится в очередь, и согласно этой очереди будет обработано главным потоком, где и выполнится метод SetProgressPos. Но тут есть один нюанс: SendMessage, как и в случае с Synchronize, приостановит выполнение нашего потока, пока основной поток не обработает сообщение. Если использовать PostMessage этого не произойдёт, наш поток отправит сообщение и продолжит свою работу, а уж когда оно там обработается - неважно. Какую из этих функций использовать - решать вам, всё зависит от задачи.
Вот, в принципе, мы и рассмотрели основные способы работы с компонентами VCL из потоков. А как быть, если в нашей программе не один новый поток, а несколько? И нужно организовать работу с одними и теми же данными? Тут нам на помощь приходят другие способы синхронизации. Один из них мы и рассмотрим. Для его реализации нужно добавить в проект модуль SyncObjs.
Критические секции
Работают они следующим образом: внутри критической секции может работать только один поток, другие ждут его завершения. Чтобы лучше понять, везде приводят сравнение с узкой трубой: представьте, с одной стороны "толпятся" потоки, но в трубу может "пролезть" только один, а когда он "пролезет" - начнёт движение второй, и так по порядку. Еще проще понять это на примере и тем же ProgressBar'ом. Итак, запустите один из примеров, приведённых ранее. Нажмите на кнопку, подождите несколько секунд, а затем нажмите еще раз. Что происходит? ProgressBar начал прыгать. Прыгает потому, что у нас работает не один поток, а два, и каждый из них передаёт разные значения прогресса. Теперь немного переделаем код, в событии onCreate формы создадим критическую секцию:
У TCriticalSection есть два нужных нам метода, Enter и Leave, соответственно вход и выход из неё. Поместим наш код в критическую секцию:
Попробуйте запустить приложение и нажать несколько раз на кнопку, а потом посчитайте, сколько раз пройдёт прогресс. Понятно, в чем суть? Первый раз, нажимая на кнопку, мы создаём поток, он занимает критическую секцию и начинает работу. Нажимаем второй - создаётся второй поток, но критическая секция занята, и он ждёт, пока её не освободит первый. Третий, четвёртый - все пройдут только по-очереди.
Критические секции удобно использовать при обработке одних и тех же данных (списков, массивов) разными потоками. Поняв, как они работают, вы всегда найдёте им применение.
В этой небольшой статье рассмотрены не все способы синхронизации, есть еще события (TEvent), а так же объекты системы, такие как мьютексы (Mutex), семафоры (Semaphore), но они больше подходят для взаимодействия между приложениями. Остальное, что касается использования класса TThread, вы можете узнать самостоятельно, в help'е всё довольно подробно описано. Цель этой статьи - показать начинающим, что не всё так сложно и страшно, главное разобраться, что есть что. И побольше практики - самое главное опыт!
Поиск по шаблону является настолько обычным занятием в разработке программного обеспечения, что для облегчения этой задачи была создана специальная технология — регулярные выражения. Узнайте, как можно использовать ее при написании кода, прочитав эту статью.
Все устройства получают входную информацию, выполняют какие-либо операции и выдают результат. Например, телефон во время разговора преобразует звуковую энергию в электрический сигнал и обратно. Двигатель потребляет топливо (пар, расщепление атомных ядер, бензин, мышечные усилия) и преобразует его в энергию. Блендер поглощает ром, лед, лайм и кюрасао и взбалтывает их в коктейль Mai Tai. (Или, если вам хочется чего-то изысканного, сделайте Bellini из шампанского и грушевого сока. Блендер – замечательное универсальное устройство.)
Так как программное обеспечение преобразует данные, то каждое приложение фактически является устройством (хоть и виртуальным, так как у него нет физических составляющих). Например, компилятор в качестве входной информации получает исходную программу и преобразует ее в двоичный исполняемый код. Программа прогнозирования погоды генерирует предсказания на основе результатов прошлых (исторических) замеров, а графический редактор обрабатывает пикселы, применяя правила к отдельным пикселам или их группам, чтобы, например, сделать изображение более четким или изменить его стиль.
Так же, как и любое другое устройство, программное обеспечение предназначено для работы с определенным исходным материалом, например, набором чисел, данными XML-схемы или протоколом. Если программе задать некорректную входную информацию — неподходящую по форме или типу, то существует большая вероятность того, что результат будет непредсказуемым и, возможно, даже катастрофическим. Как говорится: "Мусор заложишь - мусор получишь".
На самом деле для решения всех нетривиальных задач необходимо отделять правильные данные от некорректных и отклонять некорректные данные во избежание ошибок в результатах. Это, конечно же, актуально и для Web-приложений, написанных на языке PHP. Неважно, получены ли входные данные из формы для ввода с клавиатуры или в результате выполнения программного запроса Asynchronous JavaScript + XML (Ajax), прежде чем начать какие-либо вычисления, программа должна проверить входную информацию. Возможно, что числовые значения должны находиться в пределах определенного диапазона чисел или представлять собой только целые числа. Возможно, значение должно соответствовать определенному формату, например, почтового индекса. Например, почтовый индекс в США представляет собой пять цифр плюс дополнительный префикс "Plus 4", состоящий из дефиса и 4 дополнительных цифр. Возможно, другие строки также должны состоять из определенного количества символов, например, две буквы для указания аббревиатуры штата США. Строковые данные доставляют особенно много проблем: PHP-приложение должно быть начеку по отношению к злонамеренным программам-агентам, вложенным в SQL-запросы, код JavaScript или любой другой код, которые способны изменить поведение приложения или обойти защиту.
Однако каким образом программа может определить, являются ли входные данные числом или соответствуют ли определенным требованиям, например, к почтовому индексу? На самом деле для реализации проверки путем сопоставления с шаблоном необходим небольшой парсер, создающий конечный автомат, считывающий входные данные, обрабатывающий маркеры, отслеживающий состояние и выдающий результаты. Однако создание и обслуживание даже самого простого парсера может оказаться непростым делом.
К счастью, анализ на основе сопоставления с шаблоном настолько широко распространен в компьютерных технологиях, что с течением времени (примерно с момента появления UNIX®) были разработаны специальные технологии и, конечно же, механизмы обработки, чтобы облегчить рутинную работу. Регулярное выражение (regex) описывает шаблоны посредством лаконичных и удобочитаемых обозначений. Получив регулярное выражение и данные, механизм regex сообщает, совпадают ли эти данные с шаблоном, и если совпадение было обнаружено, что именно совпало.
Вот небольшой пример использования регулярного выражения, взятый из UNIX-утилиты, работающей в режиме командной строки, которая ищет заданный шаблон в содержимом одного или нескольких текстовых файлов UNIX. Команда grep -i -E '^Bat' ищет последовательность символов beginning-of-line (начало строки), обозначаемое "крышкой", [^]), за которым следуют буквы b, a, и t верхнего или нижнего регистра (ключ -i указывает на то, что при сопоставлении с шаблоном регистр не учитывается, таким образом, например, B и b - тождественны). Следовательно, для файла heroes.txt:
Листинг 1. heroes.txt
Вышеупомянутая команда grep выдаст два совпадения:
Batman
Batgirl
Регулярные выражения
PHP предлагает два программных интерфейса регулярных выражений: один -- для интерфейса переносимых операционных систем (POSIX), а второй - для регулярных выражений, совместимых с языком Perl (PCRE). В общем и целом второй интерфейс является более предпочтительным, так как PCRE сам по себе мощнее, чем POSIX, и предоставляет все операторы, используемые в языке Perl. Более подробная информация по обращению к regex-функциям POSIX представлена в документации по языку PHP (см. раздел Ресурсы). В данной статье мы сосредоточим свое внимание на свойствах PCRE.
Регулярные выражения PHP PCRE содержат операторы, позволяющие путем сопоставления находить конкретные символы или другие операторы, определенные местоположения, например, начало и конец строки, начало или конец слова. Регулярные выражения также позволяют описывать альтернативы, которые можно задать альтернативы типа "или"-"или"; повторения фиксированной, изменяемой или неопределенной длины; наборы символов (например, "любая буква от a до m"); и классы, или типы символов (печатаемые символы, знаки препинания). Специальные операторы также разрешают использовать группировку — возможность применить оператор к целой группе других операторов.
В таблице 1 показаны некоторые типичные операторы регулярных выражений. Для создания сложных выражений можно последовательно объединять элементарные операторы из таблицы 1 (и другие).
Таблица 1. Типичные операторы регулярных выражений
Оператор Значение
. (точка) Любой одиночный символ
^ (крышка) Пустая последовательность в начале строки или цепочки
$ (знак доллара) Пустая последовательность в конце строки
A Буква A верхнего регистра
a Буква a нижнего регистра
\d Любая цифра
\D Любой нецифровой символ
\w Любая буква или цифра; синоним - [:alnum:]
[A-E] Любая заглавная буква из A, B, C, D или E
[^A-E] Любой символ, за исключением заглавных букв A, B, C, D или E
X? Найти совпадение по отсутствию или наличию одной заглавной буквы X
X* Ни одной или любое количество заглавных букв X
X+ Одна или несколько заглавных букв X
X{n} Ровно n заглавных букв X
X{n,m} Не менее n и не более m заглавных букв X; если опустить m, то выражение будет искать не менее n заглавных букв X
(abc|def)+ По меньшей мере одно вхождение последовательности abc и def
В следующем примере показано типичное использование регулярного выражения. Например, для web-сайта необходимо, чтобы каждый пользователь регистрировался. Имя пользователя должно начинаться с буквы и содержать от 3 до 10 буквенно-цифровых символов. Для проверки имени пользователя на соответствие ограничениям при отправке данных в приложение можно использовать следующее регулярное выражение: ^[A-Za-z][A-Za-z0-9_]{2,9}$.
Знак "крышка" соответствует началу строки. Первый набор [A-Za-z] соответствует любой букве. Второй набор [A-Za-z0-9_]{2,9} соответствует последовательности, содержащей от 2 до 9 букв, цифр или символов подчеркивания. Знак доллара ($) соответствует концу строки.
На первый взгляд, знак доллара может показаться лишним, однако его использование важно. Если его пропустить, то условиям данного регулярного выражения будет отвечать любая строка, которая начинается с буквы, содержит от 2 до 9 буквенно-цифровых символов и любое количество других символов. Иными словами, если бы не было знака доллара как привязки к концу строки, то подошла бы недопустимо длинная строка с подходящим началом, например, "martin1234-cruft" .
Программирование на языке PHP и регулярные выражения
В PHP есть функции для поиска совпадений в тексте, замены каждого совпадения на другой текст (похоже на операцию "найти и заменить") и поиска совпадений среди элементов списка. Вот эти функции:
Чтобы показать, как работают эти функции, давайте создадим небольшое PHP-приложение, которое будет просматривать список слов на соответствие определенному шаблону. Слова и регулярные выражения будут вводиться из обычной web-формы, а результаты отображаться в браузере посредством функции simple print_r(). Эта программка пригодится, если возникнет желание проверить или отладить регулярное выражение.
PHP-код показан в листинге 2. Все входные данные берутся из обычной HTML-формы. (Для краткости эту форму и PHP-код, отслеживающий ошибки, опустим.)
Листинг 2. Сравнение текста с шаблоном
Вначале с помощью функции preg_split() строка из слов, разделенных запятыми, преобразуется в отдельные элементы. Данная функция разбивает строку в тех местах, которые соответствуют условиям регулярного выражения. В данном случае регулярное выражение представляет собой просто "," , (запятая - разделитель списка слов, указанных через запятую). Слэш в начале и в конце просто показывает начало и конец regex.
Третий и четвертый аргументы функции preg_split() необязательны, но полезны. Добавьте в третий аргумент число n целого типа, если необходимо вернуть только первые n совпадений, или -1, если необходимо вернуть все совпадения. Если в качестве четвертого аргумента задать идентификатор PREG_SPLIT_NO_EMPTY, то функция preg_split() не будет возвращать пустые результаты.
Затем каждый элемент списка слов, разделенных запятыми, корректируется (убираются начальные и конечные пробелы) с помощью функции trim() и сравнивается с заданным регулярным выражением. Функция preg_grep() существенно упрощает процесс обработки списка: просто укажите в качестве первого аргумента шаблон, а в качестве второго - массив слов для сравнения. Функция возвращает массив совпадений.
Например, если в качестве шаблона задать регулярное выражение ^[A-Za-z][A-Za-z0-9_]{2,9}$ и список слов разной длины, то можно получить результат, показанный в листинге 3.
Листинг 3. Результат работы простого регулярного выражения
Кстати, с помощью дополнительного маркера PREG_GREP_INVERT можно инвертировать операцию preg_grep() и найти элементы, которые не совпадают с шаблоном (аналогично оператору grep -v в командной строке). Заменяя 22 строку на $matches = preg_grep( "/${_REQUEST[ 'regex' ]}/", $words, PREG_GREP_INVERT ) и используя входные данные из листинга 3, мы получим Array ( [1] => 1happy [2] => hermanmunster ).
Разбор строк
Функции preg_split() и preg_grep() очень удобны. Первая из них может разбирать строку на подстроки, если подстроки разделяются определенным шаблоном. Функция preg_grep() позволяет быстро отфильтровать список.
Но что произойдет, если строку нужно разобрать на составные части, используя одно или несколько сложных правил? Например, в США номера телефонов обычно выглядят следующим образом: "(305) 555-1212," "305-555-1212," или "305.555.1212." Если убрать пунктуацию, то количество символов сократится до 10 цифр, что легко можно определить с помощью регулярного выражения \d{10}. Однако код и префикс (каждый из которых состоит из трех цифр) телефонного номера США не могут начинаться с нуля или единицы (так как нуль и единица используются как префиксы для междугородных звонков). Вместо того чтобы разбивать числовую последовательность на отдельные цифры и создавать сложный код, для верификации можно использовать регулярное выражение.
Фрагмент кода позволяющий решить эту задачу, показан в листинге 4.
Листинг 4. Проверка американского телефонного номера
Давайте пройдем по этому коду:
* Как показано в таблице 1, в регулярных выражениях используется ограниченный набор специальных символов, например, квадратные скобки ([ ]) для наименования последовательности. Если надо найти такой символ в тексте, необходимо "выделить" специальный символ в регулярном выражении, поставив перед ним обратный слэш (\). Когда символ выделен, можно задать его посик, как и любого другого символа. Если нужно найти символ точки, например, в полном составном имени хоста, то напишите \.. При желании строку можно подать в функцию preg_quote() которая выполняет автоматическую изоляцию всех специальных символов регулярных выражений, как показано в строке 1. Если поставить echo() $punctuation после первой строки, то вы должны увидеть \(\)\.-.
* В строке 2 из телефонного номера убираются все знаки пунктуации. Функция preg_replace() заменяет все символы из $punctuation — операторы из набора [ ] - пустой строкой, эффективно устраняя такие символы. Возвращаемая новая строка присваивается переменной $number.
* В строке 4 определен шаблон верифицируемого телефонного номера США.
* Строка 5 реализует сопоставление, сравнивая телефонный номер, который теперь состоит только из цифр, с шаблоном. Функция preg_match() возвращает 1, если есть совпадение. Если совпадения нет, функция preg_match() возвращает нулевое значение. Если во время обработки возникла ошибка, то функция возвращает значение False (ложно). Таким образом, чтобы проверить удачное завершение, необходимо посмотреть, было ли возвращено значение 1. В противном случае проверьте итоговое значение функции preg_last_error() (если используется PHP версии 5.2.0 или выше). Если оно не равно нулю, то, возможно, был превышен лимит вычислений, например, разрешенная глубина рекурсии регулярного выражения. Обсуждение констант и ограничений, применяемых в регулярных выражениях PHP, представлено на странице, посвященной функциям регулярных выражений PCRE (см. раздел Ресурсы).
Извлечение данных
Во многих случаях необходимо только получить ответ на вопрос: "Соответствуют ли данные шаблону?" – например, при проверке данных. Однако чаще регулярные выражения используются для подтверждения соответствия и получения информации о совпадении.
Вернемся к примеру с телефонным номером. Пусть при соответствии шаблону нам необходимо сохранить код, префикс и номер линии в отдельных полях базы данных. Регулярные выражения могут запоминать совпадающие с шаблоном данные с помощью оператора capture. Оператор capture обозначается круглыми скобками и может использоваться в любой части регулярного выражения. Операции capture можно делать вложенными для поиска подсегментов в извлеченных сегментах данных. Например, чтобы из 10-значного номера телефона извлечь код города, префикс и номер линии, можно использовать следующую строку:
/([2-9][0-9]{2})([2-9][0-9]{2})([0-9]{4})/
Если входные данные соответствуют шаблону, первые три цифры захватываются первой парой круглых скобок, следующие три цифры - второй парой, а последние 4 цифры - последним оператором. Модификация вызова функции preg_match() возвращает извлеченные данные.
Листинг 5. Возврат извлеченных данных функцией preg_match()
Если в качестве третьего аргумента функции preg_match() указать переменную, например, в нашем коде, $matches, то в качестве ее значения будет выступать список извлеченных результатов. Нулевой элемент списка (с индексом 0) - это все совпадение целиком; первый элемент - совпадение, относящееся к первой паре круглых скобок, и так далее.
Вложенные операторы capture извлекают сегменты и подсегменты фактически любой глубины. Сложность с вложенными операторами capture состоит в том, чтобы определить, в какой части массива соответствий находится каждое соответствие, например, $matches. Действует следующее правило: подсчитайте порядковый номер открывающей скобки в регулярном выражении — этот номер и будет индексом нужного совпадения в массиве соответствий.
В листинге 6 показан пример (немного надуманный) извлечения частей городского адреса.
Листинг 6. Код для извлечения городского адреса
Опять все совпадение целиком хранится по индексу 0. А где хранится номер улицы? Если считать слева направо, номер улицы проверяется \d+. Это вторая открывающая круглая скобка слева, следовательно, значением $matches[2] будет 123. В $matches[4] оказывается название города, а в $matches[6] - почтовый индекс.
Продвинутые технологии
Обработка текста – широко распространенная задача, и PHP предоставляет ряд функций, упрощающих выполнение большого числа операций. Обратите внимание на следующее:
* Функция preg_replace() может работать как с одной строкой, так и с массивом строк. Если вызвать preg_replace() для массива строк, замена будет выполнена во всех элементах массива. В этом случае код preg_replace() возвращает массив измененных строк.
* Как и во всех остальных реализациях PCRE, здесь для осуществления замены можно прибегать к сравнению с вложенным шаблоном. Для наглядности давайте рассмотрим проблему стандартизации формата телефонного номера. Заменим все знаки пунктуации точками. Наше решение показано в листинге 7.
Листинг 7. Замена знаков пунктуации точками
Сопоставление с шаблоном и, в случае совпадения, перевод в стандартный телефонный номер выполняется за один шаг.
Ваш сайт доходчиво объясняет посетителям, что заказывать нужно именно у вас, а не у ваших конкурентов? На нем хорошо видны контакты, а сделать заказ легко? Есть ли у вас возможность отслеживания активности посетителей и коэффициента конверсии? И последнее: вы знаете, сколько стоит ваш посетитель? Если вы смело можете ответить "да" на эти воспросы - ваш сайт готов к приему посетителей. Если нет - проработайте их, иначе много денег будут уходить впустую.
Все хотят "бесплатный" (поисковый) трафик, но находиться в топе поисковых систем - очень трудоемкое занятие. Однако, если вы создадите богатый контентом сайт и последуете советам из этого списка, ваш трафик будет увеличиваться сам собой и PR будет расти.
*Pay-Per-Click (PPC) - оплата за клики. Трафик с PPC-систем можно получить почти мгновенно! Google и Overture (теперь еще и Yahoo) - вот основные источники PPC-трафика, но можно попробовать и FindWhat.com. На что следует обратить внимание: Держите в голове цену своего посетителя, ставьте объявления по сотням неконкурентным ключевым словам и фразам, и отслеживайте статистику по каждому слову или фразе отдельно.
*Распространяйте свой контент в сети - пишите полезные статьи, интересные целевой аудитории. Распространяйте их среди веб-мастеров, разрешите им перепечатывать ваши тексты в обмен на размещение ссылки на ваш ресурс вида "источник: " или "по материалам сайта: ". Распространяйте ваши статьи и через каталоги статей, электронные журналы и ваш блог. На что следует обратить внимание: полезное, по возможности уникальное, содержание статей.
*Публикуйте свои пресс-релизы - периодически публикуйте пресс-релизы с новостями, которые будут интересны вашей целевой аудитории и вашим потенциальным покупателям. Поскольку пресс релизы это, фактически, новости, они публикуются быстро, и вы можете так же быстро заполучить сотни ссылок на свой сайт. На что следует обратить внимание: желательно писать пресс-релиз из 300-500 слов, и включить в него ссылку на свой ресурс. Желательно доверить распространение релизов профессионалам, которые смогут оптимизировать их по ключевым словам.
*Сделайте блог с RSS - чтобы приносить пользу, блог должен часто пополняться новыми материалами. Пусть ваш блог содержит информацию, полезную для ваших покупателей, но не заостренную на продажах и специальных предложениях. Последнее нужно делать очень аккуратно, мы советуем вообще заострять на продажах внимание, если не можете посвятить этому достаточное количество времени. Seth Godin говорит, что составляющие успешного блога это: (1) Беспристрастность, (2) Мгновенное реагирование, (3) Своевременность, (4) Тематичность - коротко и "в кассу", и (5) Дискуссия, полемика. На что следует обратить внимание: блог должен быть интересен посетителям, добавьте его во все каталоги блогов, проверяйте ваши блоговые посты в поисковиках, распространяйте свой контент через RSS.
*Набирайте односторонние входящие ссылки - все вышеперечисленное создаст хорошие входящие односторонние ссылки на ваш сайт, хотя Вы можете дополнительно покупать ссылки на других сайтах, напрямую и через биржи ссылок. Не занимайтесь обменом ссылками - от этого уже никакого толка. Убедитесь, что ссылки на ваш сайт ведут со страниц, PR которых выше 0. Если у страницы PR0, возможно Google пессимизировал ее по каким-либо причинам, в результате ссылка может нести в себе отрицательную силу. На что следует обратить внимание: удостоверьтесь, что в текстах входящих ссылок есть ключевые слова, и что ссылки текстовые. Ссылки должны быть с тематических и околотематических сайтов, а не с линкопомоек или немодерируемых каталогов. Лучшие ссылки - со страниц, количество ссылок на которых невелико.
*Разрешите другим сайтам использовать ваши материалы. Разрешайте им делать это до тех пор, пока они будут ссылаться на вас. Это позволит вам получить одностороннюю ссылку с сайтов, который бы не согласились поставить ее в других случаях. На что следует обратить внимание: старайтесь вести диалог с вебмастерами кратко, и по делу.
*Реклама через E-mail - Рекламируйтесь в электронных журналах, размещайте рекламу в почтовых рассылках, если среди получателей есть ваша целевая аудитория. На что следует обратить внимание: внимательно отслеживайте эффективность рассылок.
*Используйте возможности партнеров по бизнесу. Рекламируйтесь, используя базу клиентов ваших партнеров. John Reese продал информационный товара на $1 млн. за 24 часа, используя только базу клиентов своих партнеров, рассылая им свои предложения. Он платил партнерам 50% с продаж. На что обратить внимание: нужно знать цену своего посетителя, и хорошо проверить в действии точку продаж перед тем, как обращаться к партнерам с предложениями.
*Заведите партнерскую программу. Если Вы продаете что-нибудь, предложите партнерам комиссию за каждого привлеченного покупателя. Ссылки с сайтов партнеров будут приводить на сайт посетителей, а также увеличивать вес сайта в глазах поисковиков. На что следует обратить внимание: предложение должно быть привлекательным, обеспечьте партнеров всеми рекламными и сопуствующими материалами, дайте им доступ к статистике, чтобы они могли отслеживать переходы и активность посетителей самостоятельно, сделайте регистрацию в партнерской программе легкой. Дайте им проверенные баннеры, рекламные письма и другой инструментарий, облегчающий их задачу.
*Покупайте готовые, хорошо раскрученные сайты. Найдите сайты, которые занимают высокие позиции по вашим запросам в поисковиках, проверьте качество трафика через владельцев этих сайтов и принимайте решение о покупке. Позаботьтесь о том, чтобы права собственности на домен полностью принадлежали Вам. Вы можете разрешить бывшим владельцам использовать контент сайта, если хотите. Проверьте deleteddomains.com на предмет доменов, брошенных владельцами, которые можно зарегистрировать всего за несколько долларов. На что обратить внимание: проверьте Google PR, Alexa rank, и бэклинки сайтов до их покупки. (Я знал одного продавца, который поспорил с профессиональными оптимизаторами на предмет того, кто займет самое высокое место в поисковике за 24 часа. Он выиграл спор, просто купив сайт, который занимал первое место).
И напоследок то, с чего начинается большинство статей...
*Поисковая оптимизация (SEO). Здесь есть много технических моментов, которые следует изучить, если Вы собираетесь оптимизировать сайт самостоятельно, поэтому я советую нанять профессионала, который все сделает за вас. Не доверяйте тем, кто гарантирует вам первые места, потому что нельзя гарантировать высокие позиции в Google или Yahoo, потому что алгоритмы постоянно меняются. (Они могут гарантировать места в топе по словосочетаниям типа названия вашей компании, но это не конкурентная фраза, и она не принесет особого толка). Дизайн и структура вашего сайта - также обратите на это внимание.
3 кита поисковой оптимизации это:
*Контент
*Тематические внешние ссылки с хорошим PR
*Правильный дизайн сайта
Все перечисленное в этих 10 пунктах помогает и с контентом, и с односторонними входящими ссылками, поэтому остается только хороший дизайн. На что следует обратить внимание: не думайте о сайте как об одной странице, думайте о сайте как о сотне оптимизированных страниц, с определенной тематикой и интересных целевой аудитории.
Примечание - большая часть написанного здесь текста с примерами взята по памяти (пару лет назад изучал достаточно подробно, поэтому может что-то в алгоритмах не работать - я ведь их не копировал откуда-то, а прямо тут же и писал, так что за синтаксические ошибки не пинайте) - на данный момент я активно OLE не пользуюсь (не из-за каких-то проблем с самим OLE, а из-за отсутствия надобности в его использовании в текущий момент).
Основные преимущества, благодаря которым OLE активно используется:
* Для вызывающей базы "по барабану" - какой тип вызываемой базы (DBF или SQL)
* Объектами вызываемой базы можно управлять всеми известными методами работы с объектами в 1С (т.е. со справочниками работают методы ВыбратьЭлементы(), ИспользоватьДату() и т.п., с документами - ВыбратьДокументы() и т.п.), соответственно, можно напрямую решить - стоит отрабатывать конкретные объекты базы OLE или пропустить их.
Пример 1. Присоединение к базе 1С через OLE.
БазаОле=СоздатьОбъект("V77.Application"); // Получаем доступ к OLE объекту 1С
Локальная версия (на одного пользователя): V77L.Application
Сетевая версия: V77.Application
Версия SQL: V77S.Application
Далее вместо термина "вызываемая база" будет написано просто "база OLE", а вместо термина "вызывающая база" - "местная база"
Теперь, мы должны знать несколько параметров для запуска базы OLE: Каталог базы, имя пользователя и пароль. Ну, наверное, еще и желание запустить 1С в монопольном режиме :)
Комментарий: функции СокрЛП() стоят в примере на случай, если пользователь захочет указанные выше переменные сделать в форме диалога, а проблема при этом состоит в том, что в алгоритм программа передаст полное значение реквизита (т.е. допишет в конце значения то количество пробелов, которое необходимо для получения полной длины строки (указана в свойствах реквизита диалога)).
Пример 2. Доступ к объектам базы OLE.
Запомните на будущее как непреложный факт:
1. Из местной базы в базу OLE (и, соответственно, наоборот) напрямую методом присвоения можно перенести только числовые значения, даты и строки ограниченной длины!!! Т.е. местная база поймет прекрасно без дополнительных алгоритмов преобразования полученного значения только указанные типы значений. Кроме того, под ограничением строк подразумевается проблемы с пониманием в местной базе реквизитов объектов базы OLE типа "Строка неограниченной длины". К этому же еще надо добавить и периодические реквизиты. Естественно, под методом присвоения подразумеваются и попытки сравнить объекты разных баз в одном условии (например, в алгоритмах "Если" или "Пока" и т.п.).
2. Есть проблемы при попытке перенести "пустую" дату - OLE может ее конвертировать, например, в 31.12.1899 года и т.п. Поэтому вам лучше заранее выяснить те значения, которые могут появится в местной базе при переносе "пустых" дат, чтобы предусмотреть условия преобразования их в местной базе.
A) Доступ к константам базы OLE:
Б) Доступ к справочникам и документам базы OLE (через функцию "CreateObject"):
После создания объекта справочника или документа к ним применимы все методы, касающиеся таких объектов в 1С:
Заметьте, что если вместо "Сообщить(Спр.Наименование)" вы укажете "Сообщить(Спр.ТекущийЭлемент())", то вместо строкового/числового представления этого элемента программа выдаст вам в окошке сообщение "OLE". Именно это я и имел в виду, когда говорил, что напрямую мало что можно перенести. Т.е. не будут работать следующие методы (ошибки 1С не будет, но и результат работы будет нулевой). Рассмотрим следующий пример:
Однако, сработает следующий метод:
Отсюда вывод: возможность доступа к объектам базы 1С через OLE требуется, в основном, только для определенной задачи - получить доступ к реквизитам определенного элемента справочника или документа. Однако, не забываем, что объекты базы OLE поддерживают все методы работы с ними, в т.ч. и "Новый()", т.е. приведем пример противоположный предыдущему:
В) Доступ к регистрам базы OLE (Не сложнее справочников и документов):
Г) Доступ к перечислениям базы OLE (аналогичен константе):
ЗначениеПеречисленияOLE = БазаОле.Перечисление.Булево.НеЗнаю; // :)
Заметьте, что пользы для местной базы от переменной "ЗначениеПеречисленияOLE" особо-то и нет, ведь подобно справочнику и документу перечисление также напрямую недоступно для местной базы. Пожалуй, пример работы с ними может быть следующим (в качестве параметра условия):
По аналогии со справочниками и документами работает объект "Периодический", план счетов работает по аналогии с ВидомСубконто, ну и далее в том же духе… Отдельную главу посвятим запросу, а сейчас… стоп. Еще пункт забыл!
Ж) Доступ к функциям и процедурам глобального модуля базы OLE!
Как же я про это забыл-то, а? Поскольку при запуске базы автоматически компилируется глобальный модуль, то нам становятся доступны функции и процедуры глобального модуля (поправлюсь - только те, у которых стоит признак "Экспорт"). Плюс к ним еще и различные системные функции 1С. А доступны они нам через функцию 1С OLE - EvalExpr(). Приведем примеры работы с базой OLE:
На самом деле, в последней строке примера я исхитрился и забежал немного вперед. Дело в том, что как и запрос (см. отдельную главу), так и EvalExpr() выполняются внутри базы OLE, причем команды передавается им обычной строкой, и поэтому надо долго думать, как передать необходимые ссылки на объекты базы OLE в строке текста местной базы. Так что, всегда есть возможность поломать голову над этим…
Алгоритмы преобразования объектов в "удобоваримый вид" между базами.
Ясно, что алгоритмы преобразования нужны не только для переноса объектов между и базами, но и для такой простой задачи, как попытки сравнить их между собой.
И еще раз обращу внимание: ОБЪЕКТЫ ОДНОЙ БАЗЫ ПРЕКРАСНО ПОНИМАЮТ ДРУГ ДРУГА, ПРОБЛЕМЫ ВОЗНИКАЮТ ТОЛЬКО ТОГДА, КОГДА ВЫ НАЧИНАЕТЕ СВЯЗЫВАТЬ МЕЖДУ СОБОЙ ОБЪЕКТЫ РАЗНЫХ БАЗ, т.е. команда
будет прекрасно работать без ошибок. Не забывайте это, чтобы не перемудрить с алгоритмами!
Итак, повторяюсь, что напрямую перенести, да и просто сравнить можно только даты (причем не "пустые"), числа и строки ограниченной длины. Итак, как же нам сравнить объекты разных баз (не числа, не даты, не строки), т.е. как их преобразовать в эту самую строку/число/дату.
А) Преобразование справочников/документов базы OLE (если есть аналогичные справочники/документы в местной базе). В принципе, преобразование их было уже рассмотрено в примерах выше и сводится к поиску их аналогов в местной базе. Могу еще раз привести пример, заодно с использованием регистров:
Б) Преобразование перечислений и видов субконто (подразумевается, что в обоих базах есть аналогичные перечисления и виды субконто). Вся задача сводится к получению строкового или числового представления перечисления или вида субконто.
Не поймите это как прямую команду воспользоваться функцией Строка() или Число() :)) Нет. Для этого у нас есть обращение к уникальному представлению перечисления и вида субконто - метод Идентификатор() или ЗначениеПоНомеру(). Второй вариант не очень подходит, так как зачастую в разных базах даже перечисления бывают расположены в другом порядке, а вот идентификаторы стараются держать одинаковыми в разных базах. Отсюда вывод, пользуйтесь методом Идентификатор(). Кстати, не путайте вид субконто с самим субконто! Привожу пример преобразования:
То же самое относится и к плану счетов - принцип у него тот же, что и у вида субконто…
В) Преобразование счетов:
Во многом объект "Счет" аналогичен объекту "Справочник". Отсюда и пляшем:
Работа с запросами и EvalExpr().
Наконец-то добрались и до запросов. Надо пояснить несколько вещей, касаемых запросов (да и EvalExpr() тоже). Самое главное - компиляция текста OLE-запроса (т.е. разбор всех переменных внутри запроса), как и сами OLE-запросы выполняются внутри базы OLE и поэтому ни одна переменная, ни один реквизит местной базы там недоступны, да и запрос даже не подозревает, что его запускают по OLE из другой базы!!! Поэтому, чтобы правильно составить текст, иногда требуется не только обдумать, как передать параметры запроса в базу OLE, но и обдумать, что нужно добавить в глобальный модуль той самой OLE-базы, чтобы как-то собрать для запросы переменные!
1. Поскольку сам текст запроса и функции EvalExpr() является по сути текстом, а не набором параметров, то напрямую передать ему ссылку на элемент справочника, документ, счет и т.п. нельзя. Исключение может быть составлено для конкретных значений перечислений, видов субконто, констант, планов счетов и т.п.
2. Хоть и многим и так понятно, что я скажу дальше, но я все-таки уточню: при описании переменных в тексте запроса не забывайте, что объекты базы надо указывать напрямую, без всяких префиксов типа "БазаОле".
3. Отрабатывать запрос сложно тем, что ошибки, например, при компиляции напрямую не увидеть. Поэтому начинаем пошагово готовится к отработке запроса в базе OLE.
Вначале допишем в глобальном модуле базы OLE немного строк, которые нам помогут в работе:
Теперь начинаем потихоньку писать сам запрос. Что мы имеем:
В форме диалога местной базы несколько реквизитов диалога (либо местные переменные):
* Даты периода (НачДата и КонДата)
* Элементы справочников для фильтрации (ВыбТовар, ВыбФирма, ВыбКлиент, и т.д.)
* Какие-либо флажки (ТолькоЗамерзающийЗимойТовар , ..)
Мы начинаем писать запрос и сразу попадаем в такую ловушку:
ТекстЗапроса = " Период с НачДата по КонДата; ";
Вроде все в порядке, но такой запрос не выполнится в базе OLE, так как там понятия не имеют, что такое НачДата и КонДата :)) Ведь эти переменные действительны только для местной базы! Переписываем запрос заново:
Казалось бы все очень просто. По аналогии - если уникальность для товаров ведется по наименованию, то простой заменой слова "код" на "наименование" мы решаем вопрос и здесь. Теперь рассмотрим, когда мы выбрали группу, т.е. текст условия должен будет выглядеть так:
И здесь, правда можно проблему решить "двумями путями" :)) Первый пусть - когда мы имеем дело с двухуровне вымсправочником. Тогда проблема группы решается также просто, как и в 1-м варианте:
А если справочник очень даже многоуровневый? Вот для этого мы и используем написанную ранее функцию. Предположим, что список значений запроса с индексом массива " 1 " мы будем использовать для хранения подобных значений (например, хранить в нем группы товаров, клиентов) для хитрых условий. Итак, например, в ВыбТовар у нас указана группа товаров, а в ВыбКлиент - группа клиентов, которым мы товары группы ВыбТовар продавали. Кроме того, мы должны пропустить накладные возвратов поставщикам, и не забыть, что товары надо еще отбирать по флажку ТолькоЗамерзающийЗимойТовар:
Ну, а с реквизитами запроса разбираемся так же, как указано было выше в предыдущих разделах… И не забываем, что кроме хранения конкретных значений, можно использовать другие списки значений запроса. Например, можно заполнить какой-либо список значений запроса списком клиентов и использовать его в запросе:
Мне приходится часто менять клиентов, потому что работаю удаленно. Сделал одному – иди к другому. А еще я продаю свои программы через Интернет. При имеющейся специфике работы, заметил одну странность: примерно в двадцати пяти процентов случаев, предприятие, оплатившее работу программиста и принявшее его работу, не пользуется ею.
Начну с примеров
Фирма, продающая компьютеры, купили внушительный комплект программного обеспечения, все своевременно оплатили, купили необходимое торговое оборудование... Мы, соответственно, все им установили и приготовились запускать. Остановились на этапе, когда сотрудники фирмы, ответственные за ввод в эксплуатацию нового программного комплекса, должны внести в информацию по имеющимся в отделах остаткам. Для справки – это примерно пара сотен наименований. Но на этом все работы по проекту остановились, потому что остатки не были внесены к намеченному сроку, ни через неделю после срока, ни через месяц. Не внесены они и до сих пор, хотя прошло уже пол года. Официально мы договорились, что клиент нам позвонит, когда сотрудники освободятся и найдут время внести остатки. Сами понимаете, на небольших фирмах менеджеры – по совместительству еще и продавцы, еще и грузчики, и кассиры…
Еще пример
Достаточно крупный комбинат решил автоматизировать учет обедов собственным сотрудникам в счет зарплаты. Систему подготовили, протестировали, поставили. Обучили их специалиста. Все как обычно. Недавно узнал, что конечный пользователь нашу систему не использует. Оказывается, по весьма банальной причине: на приобретение нового компьютера руководство не выделяет средств, а на имеющемся оказалось недостаточно мощности. В свое время мы указывали им на необходимость более мощного компьютера, но в силу не совсем понятных мне внутренних интриг, этот вопрос был замят на уровне IT-отдела. В результате, автоматизация стала не эффективной, и от использования новой программы решено было отказаться.
Третий пример
Производственная фирма заказала автоматизацию учета. От фирмы был назначен специалист – постановщик ТЗ и в будущем - внедренец. Работу сделали, сдали, провели обучение внедренца (на углубленное внедрение и обучение нами всех сотрудников не выделили бюджет). Я перезвонил клиенту через пол года, чтобы узнать, не было ли замечено каких-либо багов в работе системы. С удивлением услышал, что учет по-прежнему ведется в Excel-е, потому что на глубокое, самостоятельное освоение новой системы у сотрудников нет времени, а специалист, которого мы обучали, уволился…
Хотелось бы обобщить имеющийся, скромный опыт по таким случаям, и порассуждать на тему, когда автоматизация учета становится не эффективной по вине заказчика.
Уже из приведенных примеров можно сделать одно важное заключение: во всех трех случаях явно, что администрация не была заинтересована в результате. В первом – директор не захотел останавливать продажи даже не день, чтобы довести начатое до конца, во втором и третьем был урезан бюджет, и решили сэкономить там, где этого делать было нельзя.
1. Незаинтересованность руководства в результатах
Для меня всегда было загадкой, зачем руководство той или иной фирмы вообще тратится на автоматизацию, если отчетов в excel-е достаточно, и нет желания доводить начатое до конца? Чего дирекция хочет добиться? Дань моде? Надоел ноющий главбух? Решили, что что-то пора менять, но что менять – не выяснили? Стоит напомнить, что грамотно поставленная автоматизация учета в торгово-производственных фирмах способна увеличить прибыль и уменьшить затраты. Хорошая автоматизация окупается достаточно быстро, и уже скоро начинает приносить прибыль и экономию. Но если руководство не оценило перспектив автоматизации или, что еще хуже, считает, что новый стол из красного дерева топ-менеджеру важнее нового сервера сисадмину, то вряд ли на такой фирме автоматизация будет успешной.
2. Ограниченный бюджет
Как правило, из первого следует второе. Когда руководство не совсем отдает себе отчет в том, чего они ждут от автоматизации, тогда возникают идеи, наподобие: «а давайте пригласим студента, и он все сделает, как надо», или «давайте посадим главбуха на сервер»... Я, конечно, не против подработки студентов и не сомневаюсь в потенциале российского студенчества, но хочу лишь сказать о том, что для внедрения серьезной системы учета простого умения программировать очень мало. Хороший внедренец должен уметь просчитать возможные последствия выбора той или иной стратегии автоматизации. Это достаточно кропотливая работа, требующая, прежде всего, большого практического опыта, понимание не только специфики учета предприятия, но и его неочевидных нюансов. В конце концов, такая работа требует настойчивости, потому что часто решения внедренцев могут встретить сопротивление со стороны заказчика, и нужно уметь отстоять свои предложения, основываясь, опять же, на собственном опыте, защищая интересы сопротивляющегося клиента. Вряд ли какой-либо студент, понимающий, что занимается временным, не свойственным ему делом, способен на такое. Поэтому, считаю, что экономия на уровне исполнителя – это почти гарантия неудавшейся автоматизации.
Это же относится и к неоправданной экономии на оборудовании. Как правило, сбой системы происходит в самом слабом ее звене и в самый неподходящий момент… Помню, как у одного моего клиента, смотрящего «сквозь пальцы» на предложение обновить сервер, этот сервер вдруг однажды сгорел, когда бухгалтерия делала годовой отчет. Печально было то, что архивирование данных не велось должным образом, опять же, не смотря на рекомендации: директор считал покупку пишущего cd-room (в то время) – не особенно необходимыми затратами. Систему, конечно, восстановили. Но я помню, как бухгалтерии пришлось две недели работать чуть ли не по ночам, чтобы восстановить потерянные за год данные по первичным документам. Кстати, после этого случая руководство все-таки купило в то время жутко дорогой сервер с райд-массивом…
3. Тендер на откатах
Где-то встречал в сети примерную статистику, какой процент тендеров на IT услуги в России выигрывается за счет откатов ответственному лицу. Статистика – не утешительна. Печально, что на откаты попадают в основном крупные заказчики, где сумма договора внушительна, и руководство напрямую не занимается подбором исполнителя, а поручает это собственному специалисту, который не всегда бывает доволен уровнем своей заработной платы. Практика показывает, что при таком раскладе, все работы бывают выполнены в срок, все документы подписаны, но сотрудники фирмы остаются недовольны результатами и не могут использовать внедренную систему в планируемом объеме по разным причинам. Соответственно, руководство не имеет требуемой аналитической базы и начинает выяснять, в чем причина. Такие разбирательства затягиваются надолго, часто сопровождаются кадровыми движениями и, в конечном итоге, поисками того, кто бы систему довел до ума…
4. К вопросу о лидерах отрасли
Хотел бы привести еще один пример, достаточно типичный. Фирма готова тратить деньги на автоматизацию, но не сориентировалась на рынке IT-услуг и обратилась к кому-то очень известному. В результате затраты превысили все разумные пределы, а итог оказался не совсем ожидаемым, хотя, возможно, приемлемым с натяжкой.
К сожалению, это только при покупке автомобиля можно руководствоваться рекламными буклетами, и, если позволяют средства, выбирать самое последнее из модельного ряда. В сфере IT-услуг, как показывает практика, все далеко не так, особенно в сфере автоматизации на базе продуктов фирмы «1С» фирмами-франчайзи. Если исполнитель – не на уровне масштабов компании «Intel Corporation», то его раскрученность совсем может не соответствовать качеству предлагаемых им услуг, а объемы клиентской сети, требующей постоянного сопровождения, могут не позволить заниматься новым клиентом на должном уровне. На фоне этого, стоило бы вспомнить о небольших фирмах, менее раскрученных, а потому не выигравших тендер, которые были бы просто счастливы получить крупного заказчика IT-услуг, даже с меньшей суммой договора, и были готовы отдать все силы на то, чтобы клиент остался доволен. Амбиции небольших коллективов, уровень их специалистов и заинтересованность в результатах работы часто оказываются выше, чем у раскрученных, больших компаний. Небольшие фирмы не могут допустить в работе того, что позволят себе монополии, потому что любая неудача может грозить такой фирме банкротством.
Я назвал лишь четыре, пожалуй, основных фактора, когда автоматизация не достигает результатов, и присходит это, отчасти, по вине заказчика. Наверняка, имеются и другие причины, но корень проблем, на мой взгляд, следует искать, прежде всего, в неправильной позиции руководства компании, которая выражается или в непонимании, зачем нужна автоматизация, или в неправильно выбранной стратегии решения этого вопроса. Там, где решения принимаются трезво и взвешенно, где оценивается уровень специалиста, а не его раскрученность на рынке, где руководство четко понимает, чего оно ждет от автоматизации в итоге – там все будет нормально, чего всем и желаю…
Не всегда хорошая программа стоит много денег. Не которые бесплатные программы, например, такие как VirtualDub или 7-Zip стали более популярными, чем их платные аналоги. Создание таких программ начинается с простого энтузиазма людей, которые хотят сделать вещь полезную всем. А результат работы целой команды людей всегда оказывается успешным.
3D-редактор Blender 2.45
Не всегда хорошая программа стоит много денег. Не которые бесплатные программы, например, такие как VirtualDub или 7-Zip стали более популярными, чем их платные аналоги. Создание таких программ начинается с простого энтузиазма людей, которые хотят сделать вещь полезную всем. А результат работы целой команды людей всегда оказывается успешным.
Так случилось и с программой трехмерной графики Blender. Это ещё один пример коллективной работы многих людей. И сейчас Blender является полноценным бесплатным 3D-редактором.
Внешний вид всех программ для работы с трехмерной графикой очень похож. По этому производители коммерческих пакетов для работы с 3D выпускают специальные брошюры, где подробно разъясняются отличия в «горячих клавишах» и инструментах управления сценой между их программой и приложением, с которого они хотят переманить пользователя.
Программисты, сделавшие Blender, не ставят перед собой цель заработать деньги, и им не нужно подстраиваться под тех, кто раньше работал в другом 3D-редакторе. Поэтому, открывая для себя Blender, работе с трехмерной графикой приходится учиться заново.
Необычный внешний вид Blender говорит о том, что разработчики создавали свой проект «с нуля», не привязываясь к внешнему виду прочих программ для работы с трехмерной графикой. В какой-то мере это было правильное решение, ведь только так можно было создать удобный и в то же время принципиально новый интерфейс. Казалось бы, что можно придумать удобнее нескольких окон проекций и панели с настройками объектов?
Удобнее может быть только возможность гибкой настройки интерфейса под нужды каждого пользователя. В Blender реализована технология, благодаря которой внешний вид программы изменяется до неузнаваемости. Изюминка интерфейса Blender состоит в том, что в процессе работы над трехмерной сценой можно «разбивать» окно программы на части. Каждая часть – независимое окно, в котором отображается определенный вид на трехмерную сцену, настройки объекта, линейка временной шкалы timeline или любой другой режим работы программы.
Таких частей может быть неограниченно много – все зависит от разрешения экрана. Но сколько бы окошек ни было создано, они никогда не пересекутся между собой. Размер одного зависит от размера остальных, то есть если пользователь увеличивает размер одной части, размер соседних уменьшается, но никаких "накладываний" окон друг на друга не происходит. Это невероятно удобно, и тут создателям коммерческих приложений стоило бы посмотреть в сторону Blender, чтобы взять новшество на заметку.
Еще одна сильная сторона программы – хорошая поддержка «горячих клавиш», при помощи которых можно выполнять практически любые операции. Сочетаний довольно много, и запомнить все сразу тяжело, однако их знание значительно ускоряет и упрощает работу в Blender.
Таким образом, сложным интерфейс программы кажется только с непривычки. На самом же деле, инструменты Blender расположены очень удобно. Для того чтобы это понять, нужно поработать в программе какое-то время, привыкнуть к ней.
Для создания трехмерных моделей используются полигональные и NURBS-поверхности. Имеются в Blender и инструменты сплайнового моделирования. Создание 3D-объектов производится также с использованием кривых Безье иB-сплайнов.
Инструментарий Blender столь универсален, что позволяет воссоздавать даже очень сложные органические формы. Для этой цели можно использовать метаболы и технологию «трехмерной лепки» с помощью виртуальных кистей. Редактирование формы трехмерной модели с помощью кистей производится примерно так же, как это делается в Maya. Вносить изменения в геометрию можно в режиме симметрии, что особенно важно при моделировании персонажей.
В программе можно создавать обычную анимацию, а также работать над персонажной оснасткой, строить скелет и выполнять привязку костей к внешней оболочке. Трехмерный редактор работает с прямой и инверсной кинематикой.
В программе предусмотрена и возможность работы с частицами. Система частиц может быть привязана к любому трехмерному объекту. Поток частиц управляется с помощью направляющих кривых, эффектов ветра и завихрений. Кроме этого, влияние на частицы может определяться как окрашивание, в зависимости от силы воздействия на них. Есть вариант проверить, как частицы будут отражаться от движущейся трехмерной поверхности, или заставить их подчиняться законам гравитации. С помощью статической системы частиц можно даже моделировать волосы.
Blender включает в себя симулятор флюидов, благодаря которому в программе можно моделировать «текучие» эффекты жидкостей. Нужно отметить, что эта разновидность эффектов присутствует далеко не во всех 3D-редакторах, например, в 3ds Max нет инструментов для моделирования текучих флюидов.
Создать реалистичную анимацию особенно сложно, если необходимо имитировать физически точное поведение тел. В Blender есть инструменты для просчета поведения тел в определенных условиях. В режиме реального времени можно просчитать деформацию мягких тел, а затем «запечь» ее для экономии ресурсов и оптимизации визуализации анимации. Физически точное поведение может быть определено также и для упругих тел, с последующим «запеканием» измененных параметров в анимационные кривые.
Что касается визуализации, то и тут возможности Blender на высоте. Можно рассчитывать на поддержку рендеринга по слоям, на получение эффектов смазанного движения и глубины резкости (depth of field). Также поддерживается "мультяшный" рендеринг и имитация глобального освещения (ambient occlusion). Вместе с программой удобно использовать бесплатный движок визуализации YafRay, который может похвастаться работой с HDRI, возможностями просчета каустики и глобального освещения. Есть и другие подключаемые визуализаторы, например, Indigo.
В Blender-сообществе – был выпущен первый 3D-мультфильм, полностью созданный при помощи этой программы. Короткометражный фильм Elephants Dream создавался в течение полугода командой из шести аниматоров и других специалистов, которые постоянно работали в офисе компании Montevideo, поддерживающей проект. Приложить свою руку к созданию мультфильма могли все желающие, помогая основной команде разработчиков удаленно, через интернет.
Целью проекта было показать, что Blender является полноценным 3D-редактором, который с успехом может использоваться не только студентами и школьниками в целях обучения, но и профессионалами, работающими в команде над производством сложных проектов.
Одной из особенностей проекта Elephants Dream стало то, что в интернете был выложен для свободной загрузки не только сам фильм, но и все исходные материалы, которые использовались при его создании: сцены, текстуры и т.д.
После успеха Elephants Dream CG-энтузиасты, работающие в Blender, создали ещё один анимационный проект - фильм Peach. В нем аниматоры обращают внимание общественности на другие сильные стороны Blender, которые не удалось показать в первом фильме. В частности, это касается средств для работы с мехом и шерстью. И Peach стал "забавным и пушистым".
Blender – это отличный инструмент для трехмерного моделирования и анимации. Вне всякого сомнения, у этой программы есть будущее, она постоянно совершенствуется и обрастает новыми возможностями.
Сеть всегда объединяет несколько абонентов, каждый из которых имеет право передавать свои пакеты. Но, как уже отмечалось, по одному кабелю одновременно передавать два (или более) пакета нельзя, иначе может возникнуть конфликт (коллизия), который приведет к искажению либо потере обоих пакетов (или всех пакетов, участвующих в конфликте). Значит, надо каким-то образом установить очередность доступа к сети (захвата сети) всеми абонентами, желающими передавать. Это относится, прежде всего, к сетям с топологиями шина и кольцо. Точно так же при топологии звезда необходимо установить очередность передачи пакетов периферийными абонентами, иначе центральный абонент просто не сможет справиться с их обработкой.
В сети обязательно применяется тот или иной метод управления обменом (метод доступа, метод арбитража), разрешающий или предотвращающий конфликты между абонентами. От эффективности работы выбранного метода управления обменом зависит очень многое: скорость обмена информацией между компьютерами, нагрузочная способность сети (способность работать с различными интенсивностями обмена), время реакции сети на внешние события и т.д. Метод управления – это один из важнейших параметров сети.
Тип метода управления обменом во многом определяется особенностями топологии сети. Но в то же время он не привязан жестко к топологии, как нередко принято считать.
Методы управления обменом в локальных сетях делятся на две группы:
* Централизованные методы, в которых все управление обменом сосредоточено в одном месте. Недостатки таких методов: неустойчивость к отказам центра, малая гибкость управления (центр обычно не может оперативно реагировать на все события в сети). Достоинство централизованных методов – отсутствие конфликтов, так как центр всегда предоставляет право на передачу только одному абоненту, и ему не с кем конфликтовать.
* Децентрализованные методы, в которых отсутствует центр управления. Всеми вопросами управления, в том числе предотвращением, обнаружением и разрешением конфликтов, занимаются все абоненты сети. Главные достоинства децентрализованных методов: высокая устойчивость к отказам и большая гибкость. Однако в данном случае возможны конфликты, которые надо разрешать.
Существует и другое деление методов управления обменом, относящееся, главным образом, к децентрализованным методам:
* Детерминированные методы определяют четкие правила, по которым чередуются захватывающие сеть абоненты. Абоненты имеют определенную систему приоритетов, причем приоритеты эти различны для всех абонентов. При этом, как правило, конфликты полностью исключены (или маловероятны), но некоторые абоненты могут дожидаться своей очереди на передачу слишком долго. К детерминированным методам относится, например, маркерный доступ (сети Token-Ring, FDDI), при котором право передачи передается по эстафете от абонента к абоненту.
* Случайные методы подразумевают случайное чередование передающих абонентов. При этом возможность конфликтов подразумевается, но предлагаются способы их разрешения. Случайные методы значительно хуже (по сравнению с детерминированными) работают при больших информационных потоках в сети (при большом трафике сети) и не гарантируют абоненту величину времени доступа. В то же время они обычно более устойчивы к отказам сетевого оборудования и более эффективно используют сеть при малой интенсивности обмена. Пример случайного метода – CSMA/CD (сеть Ethernet).
Для трех основных топологий характерны три наиболее типичных метода управления обменом.
Управление обменом в сети с топологией звезда
Для топологии звезда лучше всего подходит централизованный метод управления. Это связано с тем, что все информационные потоки проходят через центр, и именно этому центру логично доверить управление обменом в сети. Причем не так важно, что находится в центре звезды: компьютер (центральный абонент), как на рис. 1.6, или же специальный концентратор, управляющий обменом, но сам не участвующий в нем. В данном случае речь идет уже не о пассивной звезде (рис. 1.11), а о некой промежуточной ситуации, когда центр не является полноценным абонентом, но управляет обменом. Это, к примеру, реализовано в сети 100VG-AnyLAN.
Самый простейший централизованный метод состоит в следующем.
Периферийные абоненты, желающие передать свой пакет (или, как еще говорят, имеющие заявки на передачу), посылают центру свои запросы (управляющие пакеты или специальные сигналы). Центр же предоставляет им право передачи пакета в порядке очередности, например, по их физическому расположению в звезде по часовой стрелке. После окончания передачи пакета каким-то абонентом право передавать получит следующий по порядку (по часовой стрелке) абонент, имеющий заявку на передачу (рис. 4.8). Например, если передает второй абонент, то после него имеет право на передачу третий. Если же третьему абоненту не надо передавать, то право на передачу переходит к четвертому и т.д.
Централизованный метод управления обменом в сети с топологией звезда
Рис. 4.8. Централизованный метод управления обменом в сети с топологией звезда
В этом случае говорят, что абоненты имеют географические приоритеты (по их физическому расположению). В каждый конкретный момент наивысшим приоритетом обладает следующий по порядку абонент, но в пределах полного цикла опроса ни один из абонентов не имеет никаких преимуществ перед другими. Никому не придется ждать своей очереди слишком долго. Максимальная величина времени доступа для любого абонента в этом случае будет равна суммарному времени передачи пакетов всех абонентов сети кроме данного. Для топологии, показанной на рис. 4.8, она составит четыре длительности пакета. Никаких столкновений пакетов при этом методе в принципе быть не может, так как все решения о доступе принимаются в одном месте.
Рассмотренный метод управления можно назвать методом с пассивным центром, так как центр пассивно прослушивает всех абонентов. Возможен и другой принцип реализации централизованного управления (его можно назвать методом с активным центром).
В этом случае центр посылает запросы о готовности передавать (управляющие пакеты или специальные сигналы) по очереди всем периферийным абонентам. Тот периферийный абонент, который хочет передавать (первый из опрошенных) посылает ответ (или же сразу начинает свою передачу). В дальнейшем центр проводит сеанс обмена именно с ним. После окончания этого сеанса центральный абонент продолжает опрос периферийных абонентов по кругу (как на рис. 4.8). Если желает передавать центральный абонент, он передает вне очереди.
Как в первом, так и во втором случае никаких конфликтов быть не может (решение принимает единый центр, которому не с кем конфликтовать). Если все абоненты активны, и заявки на передачу поступают интенсивно, то все они будут передавать строго по очереди. Но центр должен быть исключительно надежен, иначе будет парализован весь обмен. Механизм управления не слишком гибок, так как центр работает по жестко заданному алгоритму. К тому же скорость управления невысока. Ведь даже в случае, когда передает только один абонент, ему все равно приходится ждать после каждого переданного пакета, пока центр опросит всех остальных абонентов.
Как правило, централизованные методы управления применяются в небольших сетях (с числом абонентов не более чем несколько десятков). В случае больших сетей нагрузка по управлению обменом на центр существенно возрастает.
Управление обменом в сети с топологией шина
При топологии шина также возможно централизованное управление. При этом один из абонентов ("центральный") посылает по шине всем остальным ("периферийным") запросы (управляющие пакеты), выясняя, кто из них хочет передать, затем разрешает передачу одному из абонентов. Абонент, получивший право на передачу, по той же шине передает свой информационный пакет тому абоненту, которому хочет. А после окончания передачи передававший абонент все по той же шине сообщает "центру", что он закончил передачу (управляющим пакетом), и "центр" снова начинает опрос (рис. 4.9).
Централизованное управление в сети с топологией шина
Рис. 4.9. Централизованное управление в сети с топологией шина
Преимущества и недостатки такого управления – те же самые, что и в случае централизованно управляемой звезды. Единственное отличие состоит в том, что центр здесь не пересылает информацию от одного абонента к другому, как в топологии активная звезда, а только управляет обменом.
Гораздо чаще в шине используется децентрализованное случайное управление, так как сетевые адаптеры всех абонентов в данном случае одинаковы, и именно этот метод наиболее органично подходит шине. При выборе децентрализованного управления все абоненты имеют равные права доступа к сети, то есть особенности топологии совпадают с особенностями метода управления. Решение о том, когда можно передавать свой пакет, принимается каждым абонентом на месте, исходя только из анализа состояния сети. В данном случае возникает конкуренция между абонентами за захват сети, и, следовательно, возможны конфликты между ними и искажения передаваемой информации из-за наложения пакетов.
Существует множество алгоритмов доступа или, как еще говорят, сценариев доступа, порой очень сложных. Их выбор зависит от скорости передачи в сети, длины шины, загруженности сети (интенсивности обмена или трафика сети), используемого кода передачи.
Иногда для управления доступом к шине применяется дополнительная линия связи, что позволяет упростить аппаратуру контроллеров и методы доступа, но заметно увеличивает стоимость сети за счет удвоения длины кабеля и количества приемопередатчиков. Поэтому данное решение не получило широкого распространения.
Суть всех случайных методов управления обменом довольно проста.
Если сеть свободна (то есть никто не передает своих пакетов), то абонент, желающий передавать, сразу начинает свою передачу. Время доступа в этом случае равно нулю.
Если же в момент возникновения у абонента заявки на передачу сеть занята, то абонент, желающий передавать, ждет освобождения сети. В противном случае исказятся и пропадут оба пакета. После освобождения сети абонент, желающий передавать, начинает свою передачу.
Возникновение конфликтных ситуаций (столкновений пакетов, коллизий), в результате которых передаваемая информация искажается, возможно в двух случаях.
* При одновременном начале передачи двумя или более абонентами, когда сеть свободна (рис. 4.10). Это ситуация довольно редкая, но все-таки вполне возможная.
* При одновременном начале передачи двумя или более абонентами сразу после освобождения сети (рис. 4.11). Это ситуация наиболее типична, так как за время передачи пакета одним абонентом вполне может возникнуть несколько новых заявок на передачу у других абонентов.
Существующие случайные методы управления обменом (арбитража) различаются тем, как они предотвращают возможные конфликты или же разрешают уже возникшие. Ни один конфликт не должен нарушать обмен, все абоненты должны, в конце концов, передать свои пакеты.
В процессе развития локальных сетей было разработано несколько разновидностей случайных методов управления обменом.
Коллизии в случае начала передачи при свободной сети
Рис. 4.10. Коллизии в случае начала передачи при свободной сети
Коллизии в случае начала передачи после освобождения сети
Рис. 4.11. Коллизии в случае начала передачи после освобождения сети
Например, был предложен метод, при котором не все передающие абоненты распознают коллизию, а только те, которые имеют меньшие приоритеты. Абонент с максимальным приоритетом из всех, начавших передачу, закончит передачу своего пакета без ошибок. Остальные, обнаружив коллизию, прекратят свою передачу и будут ждать освобождения сети для новой попытки. Для контроля коллизии каждый передающий абонент производит побитное сравнение передаваемой им в сеть информации и данных, присутствующих в сети. Побеждает тот абонент, заголовок пакета которого дольше других не искажается от коллизии. Этот метод, называемый децентрализованным кодовым приоритетным методом, отличается низким быстродействием и сложностью реализации.
При другом методе управления обменом каждый абонент начинает свою передачу после освобождения сети не сразу, а, выдержав свою, строго индивидуальную задержку, что предотвращает коллизии после освобождения сети и тем самым сводит к минимуму общее количество коллизий. Максимальным приоритетом в этом случае будет обладать абонент с минимальной задержкой. Столкновения пакетов возможны только тогда, когда два и более абонентов захотели передавать одновременно при свободной сети. Этот метод, называемый децентрализованным временным приоритетным методом, хорошо работает только в небольших сетях, так как каждому абоненту нужно обеспечить свою индивидуальную задержку.
В обоих случаях имеется система приоритетов, все же данные методы относятся к случайным, так как исход конкуренции невозможно предсказать. Случайные приоритетные методы ставят абонентов в неравные условия при большой интенсивности обмена по сети, так как высокоприоритетные абоненты могут надолго заблокировать сеть для низкоприоритетных абонентов.
[pagebreak]
Чаще всего система приоритетов в методе управления обменом в шине отсутствует полностью. Именно так работает наиболее распространенный стандартный метод управления обменом CSMA/CD (Carrier Sense Multiple Access with Collision Detection – множественный доступ с контролем несущей и обнаружением коллизий), используемый в сети Ethernet. Его главное достоинство в том, что все абоненты полностью равноправны, и ни один из них не может надолго заблокировать обмен другому (как в случае наличия приоритетов). В этом методе коллизии не предотвращаются, а разрешаются.
Суть метода состоит в том, что абонент начинает передавать сразу, как только он выяснит, что сеть свободна. Если возникают коллизии, то они обнаруживаются всеми передающими абонентами. После чего все абоненты прекращают свою передачу и возобновляют попытку начать новую передачу пакета через временной интервал, длительность которого выбирается случайным образом. Поэтому повторные коллизии маловероятны.
Еще один распространенный метод случайного доступа – CSMA/CA (Carrier Sense Multiple Access with Collision Avoidance – множественный доступ с контролем несущей и избежанием коллизий) применяющийся, например, в сети Apple LocalTalk. Абонент, желающий передавать и обнаруживший освобождение сети, передает сначала короткий управляющий пакет запроса на передачу. Затем он заданное время ждет ответного короткого управляющего пакета подтверждения запроса от абонента-приемника. Если ответа нет, передача откладывается. Если ответ получен, передается пакет. Коллизии полностью не устраняются, но в основном сталкиваются управляющие пакеты. Столкновения информационных пакетов выявляются на более высоких уровнях протокола.
Подобные методы будут хорошо работать только при не слишком большой интенсивности обмена по сети. Считается, что приемлемое качество связи обеспечивается при нагрузке не выше 30—40% (то есть когда сеть занята передачей информации примерно на 30—40% всего времени). При большей нагрузке повторные столкновения учащаются настолько, что наступает так называемый коллапс или крах сети, представляющий собой резкое падение ее производительности.
Недостаток всех случайных методов состоит еще и в том, что они не гарантируют величину времени доступа к сети, которая зависит не только от выбора задержки между попытками передачи, но и от общей загруженности сети. Поэтому, например, в сетях, выполняющих задачи управления оборудованием (на производстве, в научных лабораториях), где требуется быстрая реакция на внешние события, сети со случайными методами управления используются довольно редко.
При любом случайном методе управления обменом, использующем детектирование коллизии (в частности, при CSMA/CD), возникает вопрос о том, какой должна быть минимальная длительность пакета, чтобы коллизию обнаружили все начавшие передавать абоненты. Ведь сигнал по любой физической среде распространяется не мгновенно, и при больших размерах сети (диаметре сети) задержка распространения может составлять десятки и сотни микросекунд. Кроме того, информацию об одновременно происходящих событиях разные абоненты получают не в одно время. С тем чтобы рассчитать минимальную длительность пакета, следует обратиться к рис. 4.12.
Расчет минимальной длительности пакета
Рис. 4.12. Расчет минимальной длительности пакета
Пусть L – полная длина сети, V – скорость распространения сигнала в используемом кабеле. Допустим, абонент 1 закончил свою передачу, а абоненты 2 и 3 захотели передавать во время передачи абонента 1 и ждали освобождения сети.
После освобождения сети абонент 2 начнет передавать сразу же, так как он расположен рядом с абонентом 1. Абонент 3 после освобождения сети узнает об этом событии и начнет свою передачу через временной интервал прохождения сигнала по всей длине сети, то есть через время L/V. При этом пакет от абонента 3 дойдет до абонента 2 еще через временной интервал L/V после начала передачи абонентом 3 (обратный путь сигнала). К этому моменту передача пакета абонентом 2 не должна закончиться, иначе абонент 2 так и не узнает о столкновении пакетов (о коллизии), в результате чего будет передан неправильный пакет.
Получается, что минимально допустимая длительность пакета в сети должна составлять 2L/V, то есть равняться удвоенному времени распространения сигнала по полной длине сети (или по пути наибольшей длины в сети). Это время называется двойным или круговым временем задержки сигнала в сети или PDV (Path Delay Value). Этот же временной интервал можно рассматривать как универсальную меру одновременности любых событий в сети.
Стандартом на сеть задается как раз величина PDV, определяющая минимальную длину пакета, и из нее уже рассчитывается допустимая длина сети. Дело в том, что скорость распространения сигнала в сети для разных кабелей отличается. Кроме того, надо еще учитывать задержки сигнала в различных сетевых устройствах. Расчетам допустимых конфигураций сети Ethernet посвящена глава 10.
Отдельно следует остановиться на том, как сетевые адаптеры распознают коллизию в кабеле шины, то есть столкновение пакетов. Ведь простое побитное сравнение передаваемой абонентом информации с той, которая реально присутствует в сети, возможно только в случае самого простого кода NRZ, используемого довольно редко. При применении манчестерского кода, который обычно подразумевается в случае метода управления обменом CSMA/CD, требуется принципиально другой подход.
Как уже отмечалось, сигнал в манчестерском коде всегда имеет постоянную составляющую, равную половине размаха сигнала (если один из двух уровней сигнала нулевой). Однако в случае столкновения двух и более пакетов (при коллизии) это правило выполняться не будет. Постоянная составляющая суммарного сигнала в сети будет обязательно больше или меньше половины размаха (рис. 4.13). Ведь пакеты всегда отличаются друг от друга и к тому же сдвинуты друг относительно друга во времени. Именно по выходу уровня постоянной составляющей за установленные пределы и определяет каждый сетевой адаптер наличие коллизии в сети.
Определение факта коллизии в шине при использовании манчестерского кода
Рис. 4.13. Определение факта коллизии в шине при использовании манчестерского кода
Задача обнаружения коллизии существенно упрощается, если используется не истинная шина, а равноценная ей пассивная звезда (рис. 4.14).
Обнаружение коллизии в сети пассивная звезда
Рис. 4.14. Обнаружение коллизии в сети пассивная звезда
При этом каждый абонент соединяется с центральным концентратором, как правило, двумя кабелями, каждый из которых передает информацию в своем направлении. Во время передачи своего пакета абоненту достаточно всего лишь контролировать, не приходит ли ему в данный момент по встречному кабелю (приемному) другой пакет. Если встречный пакет приходит, то детектируется коллизия. Точно так же обнаруживает коллизии и концентратор.
Управление обменом в сети с топологией кольцо
Кольцевая топология имеет свои особенности при выборе метода управления обменом. В этом случае важно то, что любой пакет, посланный по кольцу, последовательно пройдя всех абонентов, через некоторое время возвратится в ту же точку, к тому же абоненту, который его передавал (так как топология замкнутая). Здесь нет одновременного распространения сигнала в две стороны, как в топологии шина. Как уже отмечалось, сети с топологией кольцо бывают однонаправленными и двунаправленными. Наиболее распространены однонаправленные.
В сети с топологией кольцо можно использовать различные централизованные методы управления (как в звезде), а также методы случайного доступа (как в шине), но чаще выбирают все-таки специфические методы управления, в наибольшей степени соответствующие особенностям кольца.
Самые популярные методы управления в кольцевых сетях маркерные (эстафетные), те, которые используют маркер (эстафету) – небольшой управляющий пакет специального вида. Именно эстафетная передача маркера по кольцу позволяет передавать право на захват сети от одного абонента к другому. Маркерные методы относятся к децентрализованным и детерминированным методам управления обменом в сети. В них нет явно выраженного центра, но существует четкая система приоритетов, и потому не бывает конфликтов.
Работа маркерного метода управления в сети с топологией кольцо представлена на рис. 4.15.
Рис. 4.15. Маркерный метод управления обменом (СМ—свободный маркер, ЗМ— занятый маркер, МП— занятый маркер с подтверждением, ПД—пакет данных)
По кольцу непрерывно ходит специальный управляющий пакет минимальной длины, маркер, предоставляющий абонентам право передавать свой пакет. Алгоритм действий абонентов:
1. Абонент 1, желающий передать свой пакет, должен дождаться прихода к нему свободного маркера. Затем он присоединяет к маркеру свой пакет, помечает маркер как занятый и отправляет эту посылку следующему по кольцу абоненту.
2. Все остальные абоненты (2, 3, 4), получив маркер с присоединенным пакетом, проверяют, им ли адресован пакет. Если пакет адресован не им, то они передают полученную посылку (маркер + пакет) дальше по кольцу.
3. Если какой-то абонент (в данном случае это абонент 2) распознает пакет как адресованный ему, то он его принимает, устанавливает в маркере бит подтверждения приема и передает посылку (маркер + пакет) дальше по кольцу.
4. Передававший абонент 1 получает свою посылку, прошедшую по всему кольцу, обратно, помечает маркер как свободный, удаляет из сети свой пакет и посылает свободный маркер дальше по кольцу. Абонент, желающий передавать, ждет этого маркера, и все повторяется снова.
Приоритет при данном методе управления получается географический, то есть право передачи после освобождения сети переходит к следующему по направлению кольца абоненту от последнего передававшего абонента. Но эта система приоритетов работает только при большой интенсивности обмена. При малой интенсивности обмена все абоненты равноправны, и время доступа к сети каждого из них определяется только положением маркера в момент возникновения заявки на передачу.
В чем-то рассматриваемый метод похож на метод опроса (централизованный), хотя явно выделенного центра здесь не существует. Однако некий центр обычно все-таки присутствует. Один из абонентов (или специальное устройство) должен следить, чтобы маркер не потерялся в процессе прохождения по кольцу (например, из-за действия помех или сбоя в работе какого-то абонента, а также из-за подключения и отключения абонентов). В противном случае механизм доступа работать не будет. Следовательно, надежность управления в данном случае снижается (выход центра из строя приводит к полной дезорганизации обмена). Существуют специальные средства для повышения надежности и восстановления центра контроля маркера.
Основное преимущество маркерного метода перед CSMA/CD состоит в гарантированной величине времени доступа. Его максимальная величина, как и при централизованном методе, составит (N-1)• tпк, где N – полное число абонентов в сети, tпк – время прохождения пакета по кольцу. Вообще, маркерный метод управления обменом при большой интенсивности обмена в сети (загруженность более 30—40%) гораздо эффективнее случайных методов. Он позволяет сети работать с большей нагрузкой, которая теоретически может даже приближаться к 100%.
Метод маркерного доступа используется не только в кольце (например, в сети IBM Token Ring или FDDI), но и в шине (в частности, сеть Arcnet-BUS), а также в пассивной звезде (к примеру, сеть Arcnet-STAR). В этих случаях реализуется не физическое, а логическое кольцо, то есть все абоненты последовательно передают друг другу маркер, и эта цепочка передачи маркеров замкнута в кольцо (рис. 4.16). При этом совмещаются достоинства физической топологии шина и маркерного метода управления.
Применение маркерного метода управления в шине
Рис. 4.16. Применение маркерного метода управления в шине
Информация в локальных сетях, как правило, передается отдельными порциями, кусками, называемыми в различных источниках пакетами (packets), кадрами (frames) или блоками. Причем предельная длина этих пакетов строго ограничена (обычно величиной в несколько килобайт). Ограничена длина пакета и снизу (как правило, несколькими десятками байт). Выбор пакетной передачи связан с несколькими важными соображениями.
Назначение пакетов и их структура
Информация в локальных сетях, как правило, передается отдельными порциями, кусками, называемыми в различных источниках пакетами (packets), кадрами (frames) или блоками. Причем предельная длина этих пакетов строго ограничена (обычно величиной в несколько килобайт). Ограничена длина пакета и снизу (как правило, несколькими десятками байт). Выбор пакетной передачи связан с несколькими важными соображениями.
Локальная сеть, как уже отмечалось, должна обеспечивать качественную, прозрачную связь всем абонентам (компьютерам) сети. Важнейшим параметром является так называемое время доступа к сети (access time), которое определяется как временной интервал между моментом готовности абонента к передаче (когда ему есть, что передавать) и моментом начала этой передачи. Это время ожидания абонентом начала своей передачи. Естественно, оно не должно быть слишком большим, иначе величина реальной, интегральной скорости передачи информации между приложениями сильно уменьшится даже при высокоскоростной связи.
Ожидание начала передачи связано с тем, что в сети не может происходить несколько передач одновременно (во всяком случае, при топологиях шина и кольцо). Всегда есть только один передатчик и один приемник (реже – несколько приемников). В противном случае информация от разных передатчиков смешивается и искажается. В связи с этим абоненты передают свою информацию по очереди. И каждому абоненту, прежде чем начать передачу, надо дождаться своей очереди. Вот это время ожидания своей очереди и есть время доступа.
Если бы вся требуемая информация передавалась каким-то абонентом сразу, непрерывно, без разделения на пакеты, то это привело бы к монопольному захвату сети этим абонентом на довольно продолжительное время. Все остальные абоненты вынуждены были бы ждать окончания передачи всей информации, что в ряде случаев могло бы потребовать десятков секунд и даже минут (например, при копировании содержимого целого жесткого диска). С тем чтобы уравнять в правах всех абонентов, а также сделать примерно одинаковыми для всех них величину времени доступа к сети и интегральную скорость передачи информации, как раз и применяются пакеты (кадры) ограниченной длины. Важно также и то, что при передаче больших массивов информации вероятность ошибки из-за помех и сбоев довольно высока. Например, при характерной для локальных сетей величине вероятности одиночной ошибки в 10-8пакет длиной 10 Кбит будет искажен с вероятностью 10-4, а массив длиной 10 Мбит – уже с вероятностью 10-1. К тому же выявить ошибку в массиве из нескольких мегабайт намного сложнее, чем в пакете из нескольких килобайт. А при обнаружении ошибки придется повторить передачу всего большого массива. Но и при повторной передаче большого массива снова высока вероятность ошибки, и процесс этот при слишком большом массиве может повторяться до бесконечности.
С другой стороны, сравнительно большие пакеты имеют преимущества перед очень маленькими пакетами, например, перед побайтовой (8 бит) или пословной (16 бит или 32 бита) передачей информации.
Дело в том, что каждый пакет помимо собственно данных, которые требуется передать, должен содержать некоторое количество служебной информации. Прежде всего, это адресная информация, которая определяет, от кого и кому передается данный пакет (как на почтовом конверте – адреса получателя и отправителя). Если порция передаваемых данных будет очень маленькой (например, несколько байт), то доля служебной информации станет непозволительно высокой, что резко снизит интегральную скорость обмена информацией по сети.
Существует некоторая оптимальная длина пакета (или оптимальный диапазон длин пакетов), при которой средняя скорость обмена информацией по сети будет максимальна. Эта длина не является неизменной величиной, она зависит от уровня помех, метода управления обменом, количества абонентов сети, характера передаваемой информации, и от многих других факторов. Имеется диапазон длин, который близок к оптимуму.
Таким образом, процесс информационного обмена в сети представляет собой чередование пакетов, каждый из которых содержит информацию, передаваемую от абонента к абоненту.
Передача пакетов в сети между двумя абонентами
Рис. 4.1. Передача пакетов в сети между двумя абонентами
В частном случае (рис. 4.1) все эти пакеты могут передаваться одним абонентом (когда другие абоненты не хотят передавать). Но обычно в сети чередуются пакеты, посланные разными абонентами (рис. 4.2).
Передача пакетов в сети между несколькими абонентами
Рис. 4.2. Передача пакетов в сети между несколькими абонентами
Структура и размеры пакета в каждой сети жестко определены стандартом на данную сеть и связаны, прежде всего, с аппаратурными особенностями данной сети, выбранной топологией и типом среды передачи информации. Кроме того, эти параметры зависят от используемого протокола (порядка обмена информацией).
Но существуют некоторые общие принципы формирования структуры пакета, которые учитывают характерные особенности обмена информацией по любым локальным сетям.
Чаще всего пакет содержит в себе следующие основные поля или части (рис. 4.3):
Типичная структура пакета
Рис. 4.3. Типичная структура пакета
* Стартовая комбинация битов или преамбула, которая обеспечивает предварительную настройку аппаратуры адаптера или другого сетевого устройства на прием и обработку пакета. Это поле может полностью отсутствовать или же сводиться к единственному стартовому биту.
* Сетевой адрес (идентификатор) принимающего абонента, то есть индивидуальный или групповой номер, присвоенный каждому принимающему абоненту в сети. Этот адрес позволяет приемнику распознать пакет, адресованный ему лично, группе, в которую он входит, или всем абонентам сети одновременно (при широком вещании).
* Сетевой адрес (идентификатор) передающего абонента, то есть индивидуальный номер, присвоенный каждому передающему абоненту. Этот адрес информирует принимающего абонента, откуда пришел данный пакет. Включение в пакет адреса передатчика необходимо в том случае, когда одному приемнику могут попеременно приходить пакеты от разных передатчиков.
* Служебная информация, которая может указывать на тип пакета, его номер, размер, формат, маршрут его доставки, на то, что с ним надо делать приемнику и т.д.
* Данные (поле данных) – это та информация, ради передачи которой используется пакет. В отличие от всех остальных полей пакета поле данных имеет переменную длину, которая, собственно, и определяет полную длину пакета. Существуют специальные управляющие пакеты, которые не имеют поля данных. Их можно рассматривать как сетевые команды. Пакеты, включающие поле данных, называются информационными пакетами. Управляющие пакеты могут выполнять функцию начала и конца сеанса связи, подтверждения приема информационного пакета, запроса информационного пакета и т.д.
* Контрольная сумма пакета – это числовой код, формируемый передатчиком по определенным правилам и содержащий в свернутом виде информацию обо всем пакете. Приемник, повторяя вычисления, сделанные передатчиком, с принятым пакетом, сравнивает их результат с контрольной суммой и делает вывод о правильности или ошибочности передачи пакета. Если пакет ошибочен, то приемник запрашивает его повторную передачу. Обычно используется циклическая контрольная сумма (CRC). Подробнее об этом рассказано в главе 7.
* Стоповая комбинация служит для информирования аппаратуры принимающего абонента об окончании пакета, обеспечивает выход аппаратуры приемника из состояния приема. Это поле может отсутствовать, если используется самосинхронизирующийся код, позволяющий определять момент окончания передачи пакета.
Вложение кадра в пакет
Рис. 4.4. Вложение кадра в пакет
Нередко в структуре пакета выделяют всего три поля:
* Начальное управляющее поле пакета (или заголовок пакета), то есть поле, включающее в себя стартовую комбинацию, сетевые адреса приемника и передатчика, а также служебную информацию.
* Поле данных пакета.
* Конечное управляющее поле пакета (заключение, трейлер), куда входят контрольная сумма и стоповая комбинация, а также, возможно, служебная информация.
Как уже упоминалось, помимо термина "пакет" (packet) в литературе также нередко встречается термин "кадр" (frame). Иногда под этими терминами имеется в виду одно и то же. Но иногда подразумевается, что кадр и пакет различаются. Причем единства в объяснении этих различий не наблюдается.
В некоторых источниках утверждается, что кадр вложен в пакет. В этом случае все перечисленные поля пакета кроме преамбулы и стоповой комбинации относятся к кадру (рис. 4.4). Например, в описаниях сети Ethernet говорится, что в конце преамбулы передается признак начала кадра.
В других, напротив, поддерживается мнение о том, что пакет вложен в кадр. И тогда под пакетом подразумевается только информация, содержащаяся в кадре, который передается по сети и снабжен служебными полями.
Во избежание путаницы, в данной книге термин "пакет" будет использоваться как более понятный и универсальный.
В процессе сеанса обмена информацией по сети между передающим и принимающим абонентами происходит обмен информационными и управляющими пакетами по установленным правилам, называемым протоколом обмена. Это позволяет обеспечить надежную передачу информации при любой интенсивности обмена по сети.
Пример простейшего протокола показан на рис. 4.5.
Пример обмена пакетами при сеансе связи
Рис. 4.5. Пример обмена пакетами при сеансе связи
Сеанс обмена начинается с запроса передатчиком готовности приемника принять данные. Для этого используется управляющий пакет "Запрос". Если приемник не готов, он отказывается от сеанса специальным управляющим пакетом. В случае, когда приемник готов, он посылает в ответ управляющий пакет "Готовность". Затем начинается собственно передача данных. При этом на каждый полученный информационный пакет приемник отвечает управляющим пакетом "Подтверждение". В случае, когда пакет данных передан с ошибками, в ответ на него приемник запрашивает повторную передачу. Заканчивается сеанс управляющим пакетом "Конец", которым передатчик сообщает о разрыве связи. Существует множество стандартных протоколов, которые используют как передачу с подтверждением (с гарантированной доставкой пакета), так и передачу без подтверждения (без гарантии доставки пакета). Подробнее о протоколах обмена будет рассказано в следующей главе.
При реальном обмене по сети применяются многоуровневые протоколы, каждый из уровней которых предполагает свою структуру пакета (адресацию, управляющую информацию, формат данных и т.д.). Ведь протоколы высоких уровней имеют дело с такими понятиями, как файл-сервер или приложение, запрашивающее данные у другого приложения, и вполне могут не иметь представления ни о типе аппаратуры сети, ни о методе управления обменом. Все пакеты более высоких уровней последовательно вкладываются в передаваемый пакет, точнее, в поле данных передаваемого пакета (рис. 4.6). Этот процесс последовательной упаковки данных для передачи называется также инкапсуляцией пакетов.
Многоуровневая система вложения пакетов
Рис. 4.6. Многоуровневая система вложения пакетов
Каждый следующий вкладываемый пакет может содержать собственную служебную информацию, располагающуюся как до данных (заголовок), так и после них (трейлер), причем ее назначение может быть различным. Безусловно, доля вспомогательной информации в пакетах при этом возрастает с каждым следующим уровнем, что снижает эффективную скорость передачи данных. Для увеличения этой скорости предпочтительнее, чтобы протоколы обмена были проще, и уровней этих протоколов было меньше. Иначе никакая скорость передачи битов не поможет, и быстрая сеть может передавать файл дольше, чем медленная сеть, которая пользуется более простым протоколом.
Обратный процесс последовательной распаковки данных приемником называется декапсуляцией пакетов.
Событие - это какое-либо действие, осуществляемое пользователем либо браузером. Например, когда мы щелкаем (кликаем) на ссылке - осуществляется событие, его перехватывает специальный обработчик и перенаправляет нас на нужную страницу; при наведении курсора (указателя мыши) на ссылку в строке состояния (обычно находится в нижней части окна браузера) отображается адрес, так как обработчик "наведения курсора на объект (в данном случае на ссылку)" помещает туда этот адрес и так далее...
а). onmouseout и onmouseover
Для начала наведем курсор на кнопку "Сброс" или "Отправить" и обратим внимание на строку состояния. Вы должны увидеть там надпись с объяснением значения кнопки. Теперь отведите курсор и строка состояния очистится.
Содержимое строки состояния хранится в переменной window.status. Переменная это некоторый объект (можно представить себе ящик), значение которого (содержимое которого) можно изменять. Изменение значения осуществляется операцией присваивания (=), а выглядит она следующим образом:
имя_переменной = "значение"; (какие использовать кавычки: одинарные или двойные значения не имеет)
Поэтому для того, чтобы изменить надпись в строке состояния, нам нужно присвоить переменной window.status нужное нам значение (подсказку к кнопке), а когда курсор будет убран - присвоить пустую строку("").
Вся задача сводится к тому, чтобы определить когда пользователь наводит курсор на кнопку, а когда убирает его. Для этого нужно "сказать" обработчикам этих событий выполнить нужное нам действие. Обработчик события "наведение курсора" - onmouseover, а "отведение курсора" - onmouseout.
Очень многие тэги имеют атрибуты, начинающиеся с on (onclick, onmouseout, onfocus и т. д.). Значение этих атрибутов и есть, задача которую необходимо выполнить соответствующему обработчику. То есть для обработчика onmouseout есть атрибут onmouseout, для onmouseover - onmouseover. И в итоге мы получаем следующее определение кнопок:
Как Вы видите, атрибут onmouseover имеет в качестве значения JavaScript-код: window.status='Щелкните для отправки данных', как только курсор достигает кнопки, обработчик события mouseover - onmouseover, смотрит, что хранится в атрибуте onmouseover и выполняет необходимое действие(присвоение значения переменной window.status). Аналогично действует и обработчик события onmouseout: как только курсор уводиться от кнопки (то есть выполняется событие mouseout), то обработчик события - onmouseout выполняет код, содержащийся в атрибуте onmouseout.
То же самое и со второй кнопкой.
б). <a href="Java Scriptfunction()">Function</a>
Теперь щелкните на ссылке и откроется окошко с подсказкой. Но заметьте, что окно небольших размеров и у него нет панели инструментов - такого силами html не сделаешь! В данном примере мы имеем окно размером 300x200, без панелей инструментов, содержащее документ help.html.
Для того чтобы создать такое окошко существует следующий JavaScript-код:
где:
1. helpWindow - это имя переменной (как window.status, только в данном случае имя выбирается произвольно). Эта переменная нужна для последующей работы с окном (например, закрыть его нестандартным способом - с помощью JavaScript-сценария).
- Зачем? Не проще ли указывать просто имя открывающейся страницы, например help.html?
- А если у нас две копии одной и той же страницы? Или две страницы с одинаковым именем(например, в разных папках)? Вот для того, чтобы не перепутать страницы и свободно работать именно с тем окном с которым предполагаешь и сделанно, так чтобы "окно" присваивалось переменной, так как имя переменной можно выбрать любое.
2. window.open(что-то) - это функция. Функции выполняют определенную задачу, в данном случае window.open() открывает новое окно.
3. help.html - это страница, которую нужно открыть.
4. "" - В кавычках должно быть имя окна, но оно нам не пригодится, поэтому там нулевая строка. В следующих кавычках указываются "параметры открываемого окна": оно не должно содержать панели инструментов (toolbar=0) и должно быть шириной 300 пикселей, а высотой - 200 (width=300,height=200, соответственно).
Теперь все, что нужно это по событию "щелчка" выполнить этот код, однако есть два "но". Во-первых строка очень длинная, чтобы присвоить ее какому-либо атрибуту - будет некрасиво смотреться, да и вызывать неудобства при чтении кода страницы. Во-вторых, первоначальное предназначение ссылки - это переход на другую страницу, но нам переходить никуда не нужно, нам нужно выполнить вместо этого JavaScript-код.
Первое решается написанием функции. Как я уже говорил функция выполняет некоторую задача, причем для использования функции достаточно указать ее имя. Можно не только использовать предопределенные(функции, которые имеется в языке и без нас), но и писать их самому. Обычно функции определяются(пишутся) в разделе HEAD документа, в котором используются:
"function" значит, что дальше будет написана наша функция; help() - это имя функции (оно будет указываться вместо тела функции (между { и })).
Вторая проблема решается тоже довольно просто. Адрес страницы указывается в атрибуте href, а нам надо выполнить JavaScript код вместо перехода по ссылке:
"Java Script" означает, что дальше должен идти JavaScript-код, и что он должен выполняться вместо стандартного перехода по ссылке. В данном случае наш JavaScript-код - это созданная нами функция help().
в). onclick
Нам не остается ничего более, как закрыть окно со справкой. Для этого воспользуемся кнопкой "Закрыть". Но нас интересует то, как работает эта кнопка, а имеет она следующий вид:
Дабы закрыть окно мы сделали щелчок(Click) на кнопке "Закрыть", а щелчок это нажатие и отпускание кнопки мыши, причем и то и другое должно быть произведено на одном и том же элементе (например, на кнопке). Кликая, на кнопке мы активируем обработчик события onClick, который выполняет для нас JavaScript-код, прописанный в атрибуте onclick нашей кнопки. Помните мы открывали окно? Мы писали window.open(), а здесь тоже самое только window.close(). window - это текущее окно, а close() - закрыть.
Это одно из наиболее частоупотребляемых событий.
г). onfocus и onblur
Ну что ж будем ближе подбираться к вводу требуемой от нас информации.
Как я уже говорил: элемент получает фокус когда на нем происходит нажатие кнопки мыши, или на него осуществляется переход посредством клавиши табуляции (Tab), а теряет, когда фокус получает другой элемент. Наше поле для ввода получит фокус тогда, когда пользователь решиться ввести информацию. При этом было бы удобно, чтобы текст с подсказкой ("Введите Ваше имя") автоматически выделялся и посетитель мог его удалить одним нажатием на del, а не удалять по одному символу, или выделять текст вручную. Удобство пользователя свято. Итак, для этого мы воспользуемся событием focus. Для выделения текста используется метод select(). То есть атрибутом к полю надо прописать: onfocus="this.select();", this обозначает, что выделение должно происходить именно в этом текстовом поле (а можно прописать путь и к другому, но это не целесообразно).
А теперь попробуйте ничего не изменяя (или все удалив) убрать фокус (например, щелкнув в любом месте окна, или нажав Tab). Это событие blur, я прописал в нем выполнение функции: onblur="check();". Сама же функция имеет следующий вид (в разделе head страницы с формой между <script> и </script>):
document.forms[0].name.value - это то, что введено в текстовое поле. document - это текущий документ, forms[0] - первая форма на нашей страницы (отсчет с нуля), name = имя поля (задается атрибутом name (<input name="name">)), а value это и есть нужное нам значение (то, что введенно в текстовое поле, к которому м ы и написали путь). Введенное в поле мы присваиваем переменной val (var значит, что дальше идет имя переменной), чтобы в дальнейшем каждый раз не писать весь путь целиком.
Следующее это оператор if(если). Он выглядит следующим образом:
Мы сравниваем содержание переменной val с пустой строкой ('') и с начальной строкой ('Введите Ваше имя'). Обратите внимание, что сравнение не как в математике(с одним =), а сравниваются двума ==. || - или. Функция alert выводит окно с ошибкой (то, что в скобках - это текст ошибки). То есть:
И на всякий случай приведу целиком строку с кодом поля input:
д). onreset и onsubmit
Допустим, что пользователь заполнил форму неправильно, и он хочет очистить все поля формы одновременно: для этого он воспользуется стандартной кнопкой reset. Но что если пользователь щелкнет на ней по случайности (рука дрогнет, или в суете спутает с кнопкой submit), а форма была огромная, и он долго мучился ее заполнять..., ему будет грустно, и еще он будет долго материться. Поэтому хорошо бы у него дополнительно спросить: действительно ли он хочет очистить форму.
Вообще событие reset обрабатывается до очистки формы. А чтобы отменить очистку вообще, нам просто напросто надо вернуть обработчику события значение false, то есть прописать в соответствующем атрибуте: "return false;", а чтобы продолжить очистку: "return true;". А теперь вспомним функцию, которая выдает вопрос пользователю на подтверждение чего-либо, эта функция: "confirm('Вопрос?');". При нажатии "Ok", эта функция заменяется на true, а при нажатии "Cancel" на false. То есть все что от нас требуется, это прописать в теге <form> атрибут: onreset="return confirm('Вы действительно хотите сбросить форму?');". Тогда при нажатии "Ok" там на самом деле будет "return true;", и форма будет очищена, а если "Cancel", то "return false;" и очистка формы будет отменена.
Подобным образом действует событие submit, которое возникает при попытке отправить форму. Поскольку в нашем случае форму отправлять никуда не надо, то у меня просто написано: onsubmit="return false;". И сколько бы Вы не щелкали ничего не изменится (разве что Вы JavaScript отключите).
Обычно же обработчик onsubmit используется для верификации формы (то есть проверки на заполнение всех необходимых полей, правильность их заполнения, скажем, проверка по определенному шаблону и т. п.), для этого создается функция, которая выполняет все действия. Функция должна содержать операторы "return true" и "return false", которые позволяют, заменить функцию на true или false, соответственно, в зависимости от результатов проверки (если успешно, то true, если нет false). Но верификация данных это обширная тема, которая не может быть рассмотрена здесь. Один из примеров базовой верификации я привел, когда объяснял событие blur - подобную функцию можно использовать и здесь. Тогда <form> будет содержать атрибут: onsubmit="return function();".
Но не забывайте, что нельзя ограничиваться одной лишь проверкой языком JavaScript, ибо его поддержка может быть отключена у посетителя, и тогда все Ваши труды по защите...
е). onmousedown и onmouseup
Еще одна пара событий не нашла достойного места на странице, но я ее реализовал в виде кнопки "Button". Причем это не обычная html-кнопка, она реализована в виде двух картинок. Исходная кнопка хранится в файле с именем npressed.jpg, а нажатая - pressed.jpg. Чтобы достичь эффекта нажатия кнопки нам необходимо, чтобы при при щелчке на ней(this) значение атрибута src (путь к картинке) тега <img> менялось на pressed.jpg, а при отпускании обратно на npressed.jpg. Нажатие кнопки обрабатывает onmousedown, а отпускание - onmouseup, то есть здесь все просто:
ж). onload, onunload и onabort
Обработчик события onload активируется, когда начинает загружаться графическая часть страницы (все тексты, графика и т.п.). onload является атрибутом тега <body>. Если честно я не вижу сколько бы реального применения этому событию, зато я нашел, что можно сделать с onunload. onunload это тоже атрибут тега <body>. Событие unload происходит когда мы пытаемся покинуть данную страницу (переходим по ссылке на другую, закрываем окно браузера, обновляем страницу и т. д.). Откройте еще раз окошко справки. Допустим, что пользователь прочитал справку, и хочет отправить форму, или уйдет с нашего сайта, но при этом он забыл закрыть это маленькое окошко с подсказкой, мы на выходе закроем его сами. А для этого тег <body> (у начального документа) у нас будет выглядеть следующим образом:
Вы должны бы помнить, что helpWindow это имя нашего окна (ведь именно этой переменной мы присваивали его открытие: helpWindow = window.open("help.html", "", "toolbar=0,width=300,height=200")), а метод close() закрывает это окно. Некоторые нехорошие люди используют это событие, чтобы когда посетители уходили с его страницы, появлялись какие-либо окна, так называемые pop-up.
onabort - атрибут тега <img>. Когда пользователь отменяет загрузку изображения происходит событие abort. Но отмена загрузки изображения может не входить в наши плане. И в качестве предупреждения у нас может быть написано нечто похожее на
ЗАКЛЮЧЕНИЕ
Есть некоторые события о которых я здесь нарочно не упомянул, потому что не нашел им достойного применения, но Вам они возможно пригодятся, поэтому я уделю им немного внимания.
onchange - обработчик события, который активируется, когда Вы изменяете содержимое текстового элемента или текстовой области (<TEXTAREA>) (например, когда Вы вводите или удаляете очередную букву какого-либо текстового поля).
onselect - обработчик события выбора текста. То есть это событие происходит, когда пользователь пытается выделить текст в текстовом элементе или текстовой области.
onerror - обработчик события error, которое возникает при ошибке загрузки документа или изображения (то есть onerror это атрибут тегов <body> и <img>). Оно возникает при синтаксической ошибке JavaScript-кода (но Вы ведь не будете специально делать в нем ошибки), либо ошибкой времени выполнения (например, если Ваш скрипт выполняет какие-либо вычисления и у Вас по ошибке получится так, что некое число будет делиться на ноль, а это недопустимо - это и есть одна из ошибок времени выполнения).
Так же не забывайте, что я привел лишь по одному примеру из десятков возможных на каждое событие. Здесь главное Ваша фантазия и навыки. Например, события mouseout, mouseover, mouseup, mousedown часто используются для создания выпадающих меню и других визуальных эффектов, но это весьма трудный материал, который требует более глубоких знаний, причем не одного JavaScript.
Зачастую на Web – сайтах можно встретить страницы с размещенными на них HTML - формами. Веб-формы – удобный способ получения информации от посетителей вашего сайта. Пример тому – гостевая книга, – которая обеспечивает обратную связь с посетителями и разработчиками сайта. Формы так же удобны и для разработчиков сайта при разработке CMS, которая позволяет поддерживать главное свойство сайта - актуальность. Данная статья посвящена основам создания HTML-форм, их обработке и способам передачи данных из экранных форм в PHP-сценарии.
1) Создание простой формы
Теги <form> и </form> задают начало и конец формы. Начинающий форму тег <form> содержит два атрибута: action и method. Атрибут action содержит адрес URL сценария, который должен быть вызван для обработки сценария. Атрибут method указывает браузеру, какой вид HTTP запроса необходимо использовать для отправки формы; возможны значения POST и GET.
Замечание Главное отличие методов POST и GET заключается в способе передачи информации. В методе GET параметры передаются через адресную строку, т.е. по сути в HTTP-заголовке запроса, в то время как в методе POST параметры передаются через тело HTTP-запроса и никак не отражаются на виде адресной строки.
2) Флажок (checkbox)
Флажки checkbox предлагаю пользователю ряд вариантов, и разрешает выбор нескольких из них.
Группа флажков состоит из элементов <input>, имеющих одинаковые атрибуты name и type(checkbox). Если вы хотите, чтобы элемент был отмечен по умолчанию необходимо пометить его как checked. Если элемент выбран, то сценарию поступит строка имя=значение, в противном случае в обработчик формы не придет ничего, т.е. не выбранные флажки вообще никак не проявляют себя в переданном наборе данных.
Пример:
3) Переключатель(radio)
Переключатели radio предлагают пользователю ряд вариантов, но разрешает выбрать только один из них.
Переключатель (radio) имеет атрибуты name, type и value. Атрибут name задает имя переключателя, type задает тип radio, а атрибут value задает значение. Если пользователь выберет переключатель, то сценарию будет передана строка имя=значение. При необходимости можно указать параметр checked, который указывает на то, что перключатель будет иметь фокус (т.е. будет отмечен по умолчанию) при загрузке страницы. Переключатели также можно объединять в группы, для этого они должны иметь одно и тоже имя.
Пример:
4) Кнопка сброса формы(Reset)
При нажатии на кнопку сброса(reset), все элементы формы будут установлены в то состояние, которое было задано в атрибутах по умолчанию, причем отправка формы не производиться.
Пример:
5) Выпадающий список (select)
Тэг <select> представляет собой выпадающий или раскрытый список, при этом одновременно могут быть выбраны одна или несколько строк.
Список начинается с парных тегов <select></select>. Теги <option></option> позволяют определить содержимое списка, а параметр value определяет значение строки. Если в теге <option> указан параметр selected, то строка будет изначально выбранной. Параметр size задает, сколько строк будет занимать список. Если size равен 1, то список будет выпадающим. Если указан атрибут multiple, то разрешено выбирать несколько элементов из списка(при size = 1 не имеет смысла).
При передаче данных выпадающего списка сценарию передается строка имя=значение, а при раскрытом списке передается строка имя=значение1&имя=значение2&имя=значениеN.
6) Текстовое поле (text)
Позволяет пользователям вводить различную информацию.
При создании обычного текстового поля размером size и максимальной допустимой длины maxlength символов, атрибут type принимает значение text. Если указан параметр value, то поле будет содержать отображать value-текст. При создании поля не забывайте указывать имя поля, т.к. этот атрибут является обязательным.
Пример:
7) Поле для ввода пароля (password)
Полностью аналогичен текстовому полю, за исключением того что символы, набираемые пользователем, не будут отображаться на экране.
Пример:
8) Многострочное поле ввода текста (textarea)
Многострочное поле ввода текста позволяет отправлять не одну строку, а сразу несколько. По умолчанию тег создает пустое поле шириной в 20 символов и состоящее из двух строк.
Многострочное поле ввода текста начинается с парных тегов <textarea></textarea>. Тэг name задает имя многострочного поля. Также можно указать ширину поля(cols) и число строк(rows). При необходимости можно указать атрибут readonly, который запрещает редактировать, удалять и изменять текст, т.е. текст будет предназначен только для чтения. Если необходимо чтобы текст был изначально отображен в многострочном поле ввода, то его необходимо поместить между тэгами <textarea></textarea>.
Пример:
9) Скрытое текстовое поле
Позволяет передавать сценарию какую то служебную информацию, не отображая её на странице.
Скрытое поле начинается с тега <input>, атрибуты которого являются name, type и value. Атрибут name задает имя поля, type определяет тип поля, а атрибут value задает значение поля.
Пример:
10) Кнопка отправки формы (submit)
Служит для отправки формы сценарию.
При создании кнопки для отправки формы необходимо указать 2 атрибута: type=“submit” и value=”Текст кнопки”. Атрибут name необходим если кнопка не одна, а несколько и все они созданы для разных операций, например кнопки "Сохранить", "Удалить", "Редактировать" и т.д. После нажатия на кнопку сценарию передается строка имя=текст кнопки.
11) Кнопка для загрузки файлов (browse)
Служит для реализации загрузки файлов на сервер. Объект browse начитается с парных тегов <form></form>. Начинающий тэг <form> содержит необходимый атрибут encrypt. Атрибут encrypt принимает значение multipart/form-data, который извещает сервер о том, что вместе с обычной информацией посылается и файл. При создании текстового поля также необходимо указать тип файла – “file”.
12) Рамка (fieldset)
Объект fieldset позволяет вам нарисовать рамку вокруг объектов. Имеет закрывающий тэг </fieldset>. Заголовок указывается в тэгах <legend></legend>. Основное назначение объекта – задавание различных стилей оформления.
Пример:
Обработка форм
Все данные, которые вы хотите получить из HTML-формы в PHP сценарий обрабатываются с помощью суперглобальных массивов $_POST или $_GET, в зависимости от указанного в атрибуте method метода передачи данных.
Задача: Вам необходимо получить данные из текстового поля и многострочного поля ввода и передать их сценарию.
Решение: Необходимо создать HTML форму и PHP – сценарий для обработки формы.
Обсуждение:
Создадим два файла: form.html и action.php. В файле form.html будет содержаться html-форма с текстовым полем mytext и текстовой областью msg:
В этой html-форме нас интересует 3 атрибута: action который указывает путь к обработчику формы, имя текстового поля (mytext) и имя многострочного поля вода (msg). Также в форме присутствует кнопка, при нажатии на которую происходит передача данных.
После того как html-форма готова нам необходимо создать обработчик формы action.php:
После того как мы введем любые значение в текстовые поля и нажмем на кнопку "Отправить данные" html-форма отправить значения сценарию action.php.
После этого в переменных $text и $msg будут содержаться значения текстового поля и многострочного поля ввода соответственно, значения которых взяты из суперглобальных переменных $_POST.
Если вы хотите, чтобы в многострочном текстовом поле соблюдалось html-форматирование, то используйте функцию nl2br():
Задача: Пусть необходимо создать выпадающий список с годами с 2000 по 2050.
Решение: Необходимо создать HTML форму c элементом SELECT и PHP – сценарий для обработки формы.
Обсуждение:
Для начала создадим два файла: form.html и action.php. В файле form.html будет содержаться html-форма с выпадающим списком. Причем значения в списке можно указать двумя способами:
I. Ввод данных вручную:
II. Ввод данных через цикл:
Как видно, второй пример с циклом, более компактный. Думаю, не стоит приводить скрипт обработчика данной формы, потому что он обрабатывается точно так же как текстовое поле, т.е. значения списка можно извлечь из суперглобального массива $_POST.
Задача: Загрузка файла на сервер
Решение: Необходимо создать HTML форму и PHP – сценарий для обработки файла.
Описание:
Создадим HTML-форму для отправки файла на сервер.
В данной html-форме присутствует элемент browse, который открывает диалоговое окно для выбора файла для загрузки на сервер. При нажатии на кнопку "Передать файл", файл передается сценарию-обработчику.
Затем необходимо написать сценарий обработчик action.php. Перед написание обработчика необходимо определиться в какой каталог мы будет копировать файл:
Замечание Если вы доверяете пользователям закачивать на ваш сервер любые файлы, нужно быть предельно осторожным. Злоумышленники могут внедрить «нехороший» код в картинку или файл и отправить на сервер. В таких случаях нужно жестоко контролировать загрузку файлов.
Данный пример демонстрирует создание каталога и копирование файла в этот каталог на сервер.
Также хотел бы продемонстрировать пример с элементом checkbox. Этот элемент немного отличается от других элементов тем, что если не один из элементов checkbox’a не выбран, то суперглобальная переменная $_POST вернет пустое значение:
Потоки всегда создаются в контексте какого-либо процесса, и вся их жизнь проходит только в его границах. На практике это означает, что потоки исполняют код и манипулируют данными в адресном пространстве процесса. Если два или более потока выполняются внутри одного процесса, они делят одно адресное пространство.
Любой поток (thread) состоит из двух компонентов:
объекта ядра, через который ОС управляет потоком. Там же хранится статистическая информация о потоке.
Стека потока, который содержит параметры всех функций и локальные переменные, необходимые потоку для выполнения кода.
Потоки могут выполнять один и тот же код, манипулировать одними и теми же данными, а также совместно использовать описатели объектов ядра, поскольку таблица описателей создается не в отдельных потоках, а в процессах.
Потоки используют намного меньше ресурсов системы, чем процессы, поэтому все задачи, требующие параллельного выполнения нескольких подзадач, стоит решать по возможности с помощью потоков, не прибегая к созданию нескольких процессов.
Обычная структура многопоточного приложения рассчитана на одновременное исполнение нескольких подзадач. Однако стоит помнить, что, создавая многопоточное приложение, нам придется заботиться о сохранности и ликвидности, общих для всех потоков, данных.
Создание потока.
Первичный поток, который присутствует в программе, начинает свое выполнение с главной функции потока типа WinMain.
Для создания вторичного потока необходимо создать и для него входную функцию, которая выглядит примерно так:
Имя у функции вторичного потока, в отличии от первичного, может быть любым однако, при наличии нескольких разных потоков, назвать функции необходимо по-разному, иначе система создаст разные реализации одной и той же функции.
Когда поток закончит свое исполнение, он вернет управление системе, память, отведенная под его стек, будет освобождена, а счетчик пользователей его объекта ядра "поток" уменьшится на 1. Когда счетчик обнулится, этот объект ядра будет разрушен.
Для создания своего потока необходимо использовать функцию CreateThread:
При каждом вызове этой функции система создает объект ядра (поток). Это не сам поток, а компактная структура данных, которая используется операционной системой для управления потоком и хранит статистическую информацию о потоке.
Система выделяет память под стек потока из адресного пространства процесса. Новый поток выполняется в контексте того же процесса, что и родительский поток. Поэтому он получает доступ ко всем описателям объектов ядра, всей памяти и стекам всех потоков в процессе. За счет этого потоки в рамках одного процесса могут легко взаимодействовать друг с другом.
CreateThread - это Windows-функция, создающая поток. Если вы пишете код на С/С++ не вызывайте ее. Вместо нее Вы должны использовать _beginthreadex из библиотеки Visual C++. Почему это так важно в наших следующих выпусках.
Параметры функции CreateThread.
LpThreadAttributes - является указателем на структуру LPSECURITY_ATTRIBUTES. Для присвоения атрибутов защиты по умолчанию, передавайте в этом параметре NULL.
DwStackSize - параметр определяет размер стека, выделяемый для потока из общего адресного пространства процесса. При передаче 0 - размер устанавливается в значение по умолчанию.
LpStartAddress - указатель на адрес входной функции потока.
LpParameter - параметр, который будет передан внутрь функции потока.
DwCreationFlags - принимает одно из двух значений: 0 - исполнение начинается немедленно, или CREATE_SUSPENDED - исполнение приостанавливается до последующих указаний.
LpThreadId - Адрес переменной типа DWORD в который функция возвращает идентификатор, приписанный системой новому потоку.
Завершение потока
Поток можно завершит четырьмя способами:
функция потока возвращает управление (рекомендуемо);
поток самоуничтожается вызовом функции ExitThread;
другой поток процесса вызывает функцию TerminateThread;
завершается процесс, содержащий данный поток.
Все способы , за исключением рекомендуемого, являются нежелательными и должны использоваться только в форс-мажорных обстоятельствах.
Функция потока, возвращая управление, гарантирует корректную очистку всех ресурсов, принадлежащих данному потоку. При этом:
любые С++ объекты, созданные данным потоком, уничтожаются соответствующими деструкторами;
система корректно освобождает память, которую занимал стек потока;
система устанавливает код завершения данного потока. Его функция и возвращает;
счетчик пользователей данного объекта ядра (поток) уменьшается на 1.
При желании немедленно завершить поток изнутри используют функцию ExitThread(DWORD dwExitCode).
При этом освобождаются все ресурсы ОС, выделенные данному потоку, но С С++ ресурсы (например, объекты классов С++) не очищаются. Именно поэтому не рекомендовано завершать поток, используя эту функцию.
Если же вы ее использовали, то кодом возврата потока будет тот параметр, который вы передадите в данную функцию.
Как и для CreateThread для библиотеки Visual C++ существует ее аналог _endthreadex, который и стоит использовать. Об причинах в следующем выпуске.
Если появилась необходимость уничтожить поток снаружи, то это моет сделать функция TeminateThread.
Эта функция уменьшит счетчик пользователей объекта ядра (поток) на 1, однако при этом не разрушит и не очистит стек потока. Стек будет существовать, пока не завершится процесс, которому принадлежит поток. При задачах, постоянно создающих и уничтожающих потоки, это приводит к потере памяти внутри процесса.
При завершении процесса происходит следующее.
Завершение потока происходит принудительно. Деструкторы объектов не вызываются, и т.д. и т.д.
При завершении потока по такой причине, связанный с ним объект ядра (поток) не освобождается до тех пор, пока не будут закрыты все внешние ссылки на этот объект.
Такие типы данных, как int, float, char и long, являются неотъемлемой частью C/C++ и вам не нужно писать никакого кода, чтобы сообщить компилятору о том, что означают эти слова. C/C++ позволяет вам также объ-являть свои собственные, специальные типы данных. В следующем разделе вы узнаете, как объявлять структуры, которые можно отнести к специальным типам данных.
Как вы уже знаете, переменная в C/C++ объявляется следующим образом:
В приведенном операторе iMyVariable объявлена как целая переменная. А вот объявление переменной типа char:
Напишите следующий исходный код:
В коде, который вы написали, имеются два оператора #include:
Файл iostream.h включен в код, поскольку в main(void) используется cout. Файл string.h включается потому, что в main(void) используется функция strcpy() (объявленная в файле string.h). Затем вы объявляете структуру:
Обратите внимание на синтаксис объявления структуры. Оно начинается с ключевого слова struct, за которым следует имя типа-структуры. В этой программе типу структуры присвоено имя MYSTRUCTURE. Затем следует собственно определение структуры, заключенное в фигурные скобки. Не забудьте поставить точку с запятой после закрывающей фигурной скобки. Теперь посмотрите на код внутри фигурных скобок:
Это означает, что MYSTRUCTURE состоит из строки с именем sName и целого с именем iAge, sName и iAge называются элементами данных структуры; Вы объявили их "Внутри" cтруктуры MYSTRUCTURE. Код в main(void) объявляет переменную с именем MyStructure типа MYSTRUCTURE:
Вспомните, что в объявляли переменную iNum1 следующим образом:
Когда вы объявляете MyStructure , которая будет структурой типа MYSTRUCTURE, рассматривайте переменную MyStructure аналогично переменной iNum1. MyStructure - это имя переменной, а ее типом является MYSTRUCTURE точно так же, как типом переменной iNum1 является int. (Обратите внимание, что по традиции имя структуры составлено из символов нижнего регистра или в нем смешаны символы нижнего и верхнего регистров, как, например, в имени MyStructure, но в имени типа структуры используются только символы верхнего регистра, как, например, в MYSTRUCTURE.)
Следующий оператор в main(void) копирует строку 'Andy' в элемент данных MyStructure.sName:
В этом операторе обращение к элементу данных sName записано как MyStructure.sName Следующий оператор присваивает значение 13 элементу данных iAge cтруктуры MyStructure: MyStructure.iAge - 13; Затем выполняется ряд операторов вывода cout:
Сложив все вместе, мы видим, что программа MyStruct выводит сообщение My name is Andy and I am 13 years old. (Меня зовут Andy и мне 13 лет)
Данная публикация предназначена для тех кто делает первые шаги в PHP-программировании.
В статье приводятся примеры часто используемых методов работы с текстом.
После каждого примера идет краткое описание используемых функций.
Данная публикация предназначена для тех кто делает первые шаги в PHP-программировании. В статье приводятся примеры часто используемых методов работы с текстом. После каждого примера идет краткое описание используемых функций, описания взяты из официального руководства PHP. Примеры будут пополнятся по мере поступления вопросов от читателей.
Урок №1
Заменяем {text}, например на слово "студёную", строгий регистр, т.е. заменится только {text}, но не {TexT}:
str_replace (search, replace, subject)
Эта функция возвращает строку или массив со всеми вхождениями search в subject, заменёнными данным значением replace.
Урок №2
Заменяем "летнюю", например на слово "зимнюю", нестрогий регистр, т.е. заменится "летнюю", "ЛЕТНЮЮ", "Летнюю", "леТНюю" и т.д.
preg_replace (pattern, replacement, subject)
Эта функция выполняет поиск и замену регулярного выражения.
Ищет в subject совпадения с pattern и замещает их replacement, где pattern - это регулярное выражение, с которыми мы познакомся позже.
Урок №3
Считываем первые 5 символов из текста:
substr (string, start [, length])
Substr возвращает часть строки string, специфицированную параметрами start и length.
Если start положительный, возвращаемая строка начинается со start'овой позиции в string, отсчитываемой от нуля. Например, в строке 'abcdef' символ в позиции 0 это 'a', символ в позиции 2 это 'c', и так далее.
Урок №4
Считываем последние 5 символов из текста:
Урок №5
Удаляем первые 5 символов из текста:
Урок №6
Удаляем последние 5 символов из текста:
Урок №7
Считываем символы с 3-го по 7-ой:
Урок №8
Заменяем все буквы в тексте на маленькие:
strtolower (string)
Возвращает string со всеми алфавитными символами, конвертированными в нижний регистр.
Урок №9
Заменяем все буквы в тексте на большие:
string strtoupper (string)
Возвращает string со вмеси алфавитными символами, конвертированными в верхний регистр.
Урок №10
Меняем все буквы в тексте на маленькие и делаем самую первую букву заглавной:
ucfirst (string)
Возвращает строку с первым символом в верхнем регистре, если это алфавитный символ.
Урок №11
Замена нескольких пробелов на один:
Урок №12
Удаление лишних пробелов по левому и правому краю текста:
trim (string)
Эта функция возвращает строку с вырезанными в начале и конце строки string пробелами.
Урок №13
Удаление лишних пробелов по левому краю текста:
ltrim (string)
Эта функция возвращает строку с вырезанными пробелами в начале string.
Урок №14
Удаление лишних пробелов по правому краю текста:
rtrim (string)
Эта функция возвращает строку с вырезанными пробелами в конце string.
Урок №15
Удаление всех тэгов:
strip_tags (str [, allowable_tags])
Эта функция пытается вернуть строку str с вырезанными тэгами HTML и PHP. Выдаёт ошибку с предупреждением в случае наличия неполных или ложных тэгов.
Вы можете использовать необязательный второй параметр для специфицирования тэгов, которые не должны вырезаться.
Урок №16
Удаление всех тэгов, кроме <b> и <i>:
Урок №17
Проверяем, есть ли в тексте слово "разогнём", нестрогий регистр, т.е. ищется и "РаЗогНЁМ", и "РАЗОГНЁМ" и "разогнём" и т.д.:
preg_match (pattern, subject)
Ищет в subject совпадения с регулярным выражением, заданным в pattern.
Урок №18
Проверяем, есть ли в тексте слово "надо", строгий регистр, т.е. ищется только слово "надо":
strstr (haystack, needle)
Возвращает часть строки haystack от первого вхождения needle до конца haystack.
Если needle не найден, возвращает FALSE (ложь).
Урок №19
Считываем первые 6 слов из текста:
explode (separator, string)
Возвращает массив строк, каждая из которых является подстрокой строки string и сформирована путём разделения строки по границам образованными сепаратором строки separator.
Операция .= добавляет к строковой переменной новые символы.
Урок №20
Конвертируем текст с кодировком windows-1251 в кодировку koi8-r:
convert_cyr_string (str, from, to)
Эта функция возвращает данную строку, конвертированную из одного набора символов кириллицы в другой.
Аргументы from и to это односимвольные аргументы, представляющие исходный и целевой наборы кириллицы. Поддерживаются типы:
k - koi8-r
w - windows-1251
i - iso8859-5
a - x-cp866
d - x-cp866
m - x-mac-cyrillic
Урок №21
Используем в качестве разделителя "||" (две вертикальных черты):
Урок №22
Заменяем <b> на <b> и </b> на </b>:
htmlspecialchars (string string)
Некоторые символы имеют в HTML специальное значение и должны быть представлены мнемониками HTML для сохранения своего значения.
Эта функция возвращает строку с выполненной конвертацией.
Используется для того, чтобы всякие нехорошие человеки не написали в вашей гостевой (например) нежелательных тегов, испортив тем самым её внешний вид.
Хотя эти и не единственное где можно применить данную функцию, мы поговорим об этом при случае 1
& (амперсанд) становится &
" (двойная кавычка) становится "
' (одинарная кавычка) становится '
< (меньше) становится <
> (больше) становится >