98
журнал для профессиональных системных администраторов, вебмастеров и программистов №1 октябрь 2002 Настройка почтового сервера: postfix+imap+mysql Что такое SAMBA? Python+администрирование Настройка почтового сервера: postfix+imap+mysql Что такое SAMBA? Python+администрирование Философия Perl «Стеммер» — программа морфологического анализа Оптимизация работы с памятью в Perl Java – магия отражения Философия Perl «Стеммер» — программа морфологического анализа Оптимизация работы с памятью в Perl Java – магия отражения Сканер портов: пример реализации Программирование сокетов Сканер портов: пример реализации Программирование сокетов

001 Системный Администратор 10 2002

Embed Size (px)

DESCRIPTION

Философия Perl «Стеммер» — программа морфологического анализа Оптимизация работы с памятью в Perl Java – магия отражения Философия Perl «Стеммер» — программа морфологического анализа Оптимизация работы с памятью в Perl Java – магия отражения №1 октябрь 2002 БЕСПЛАТНАЯ РЕКЛАМА БЕСПЛАТНОГО ПРОДУКТА WWW.KERNEL.ORG Успехов! Искренне Ваш, Александр Михалев

Citation preview

Page 1: 001 Системный Администратор 10 2002

журнал для профессиональных системных администраторов,вебмастеров и программистов

№1 октябрь 2002

Настройка почтового сервера: postfix+imap+mysqlЧто такое SAMBA?Python+администрирование

Настройка почтового сервера: postfix+imap+mysqlЧто такое SAMBA?Python+администрирование

Философия Perl«Стеммер» — программа морфологического анализаОптимизация работы с памятью в PerlJava – магия отражения

Философия Perl«Стеммер» — программа морфологического анализаОптимизация работы с памятью в PerlJava – магия отражения

Сканер портов: пример реализацииПрограммирование сокетовСканер портов: пример реализацииПрограммирование сокетов

Page 2: 001 Системный Администратор 10 2002

БЕСПЛАТНАЯРЕКЛАМА

БЕСПЛАТНОГОПРОДУКТА

WWW.KERNEL.ORG

Page 3: 001 Системный Администратор 10 2002

Давайте знакомиться — «Системный администратор». В октябре вышелв свет первый номер нового журнала, который, как я надеюсь, облегчит жизньне только системным администраторам, но и программистам сетевых и сервер-ных приложений, вебмастерам, любознательным студентам и всем тем, кто немыслит своей жизни без Интернета.

В этом номере Вы найдете полезные советы, касающиеся программирова-ния на языках Perl и Java. Ведущий разработчик системы «Рамблер» АндрейКоваленко делится своим опытом в области морфологического анализа. Дани-ил Алиевский откроет секреты магии Java в статье «Java - магия отражений». Спомощью материала Вячеслава Калошина Вы сможете своими руками устано-вить и настроить удобный почтовый сервер. Проектировщикам и студентам стар-ших курсов будет интересна рубрика «Образование» — в ней представлен об-ширный теоретический материал-исследование, посвященный проектированиюреляционных баз данных. Роман Сузи решает некоторые задачи администри-рования с помощью языка Python.

Современные дамы настроены не менее решительно: удастся ли им отвое-вать место в нише компьютерных «гуру», давно и весьма основательно занятоймужчинами? Обо всем об этом — на страницах первого номера. Впрочем, всечто Вы будете читать - это результат творческой деятельности авторов. А воп-рос, почему они используют тот или иной продукт, Вы можете задать им личнона форуме нашего сайта www.samag.ru . Не сомневаюсь, что и Вам есть чемподелиться, поэтому ждем Ваших статей и интересных материалов.

Успехов!Искренне Ваш,

Александр Михалев

Page 4: 001 Системный Администратор 10 2002

2

Хеви ХардвэрУстановка и настройка коммутаторовCISCO CATALYST серий 2900XL и 3500Всеволод Стахов8-13

Удобная почтовая системаВячеслав Калошин

В статье «Удобная почтовая система» подробно описывается установка и настройкапочтового сервера на базе связки postfix+imapчерез СУБД mySQL.

14-19

Миграция с Windows на LinuxДмитрий Галышев

Автор материала «Миграция c Windows на Linux»рассматривает последовательность действий, не-обходимо для переноса файлового сервера изWindows NT на Linux и требования к установкеSAMBA-сервера.

20-23

Что такое SAMBA?Сергей Еремчук24-27

Python в администрировании сервера:почему бы и нет?Роман Сузи28-32

Работа с текстом, или философия PerlКоновалов Евгений34-41

Эффективное использование памятив Perl при работе с большими строкамиДаниил Алиевский42-45

«Стеммер»Морфологический анализ длянебольших поисковых системАндрей Коваленко46-49

Java - магия отраженийДаниил Алиевский50-57

ColdFusion или, возможно, лучшеерешение для создания динамическихсайтовАлександр Меженков58-61

Программирование сервисов в Windows2000Всеволод Стахов62-66

АДМИНИСТРИРОВАНИЕ ПРОГРАММИРОВАНИЕ

С О Д Е Р Ж А Н И Е С О Д Е Р Ж А Н И Е

Page 5: 001 Системный Администратор 10 2002

3№1, октябрь 2002

Анализатор сетевого трафикаВладимир Мешков68-71

Сканер портов: пример реализацииВладимир Мешков

«Сканер портов» - Целью данной статьи являетсяописание принципов функционирования и внутрен-него устройства простого сканера портов TCP про-токола.

72-76

Программирование сокетовВсеволод Стахов78-82

Взаимные функциональныезависимостиАндрей Филиппович

«Взаимные функциональные зависимости» —исследование проведено по наиболее распростра-ненным учебникам, посвященным проектированиюреляционных баз данных. Рассматриваются ошиб-ки и нетривиальные моменты, освещаемыев подобной литературе.

84-89

CommerceML - стандарт обменакоммерческой информациейв формате XMLЕлена Ртищева90-93

Женщина и компьютер

Уступите место женщинеЕвгения Саблина94

Почему мало женщин вкомпьютерных компанияхВячеслав Михалев95

Анонс96

6, 77

СЕТИ О Б РА З О В А Н И Е

ТЕНДЕНЦИИ4-5

FAQ PERL

С О Д Е Р Ж А Н И Е С О Д Е Р Ж А Н И Е

Page 6: 001 Системный Администратор 10 2002

4

тенденции

Дырка в PGP 7.1В PGP обнаружилась очень не-

приятная дырочка: при обработкедлинных имен файлов в шифрован-ном архиве происходит переполне-ние буфера, со всеми вытекающи-ми последствиями. Патчик к 7.1.0и 7.1.1 выпустила NetworkAssociates. На сайте PGP.COM, ко-торой NA недавно продала всю ли-нейку продуктов PGP, и котораяуже анонсировала новую версию(см. http://www.bugtraq.ru/rsn/archive/2002/08/18.html) 8.0 покатихо.

Источник: CNet [http://n e w s . c o m . c o m / 2 1 0 0 - 1 0 0 1 -956815.html?tag=cd_mh ]

Не доверяй никомуОбнаруженная недавно пробле-

ма с ошибочной реализацией SSLв браузерах Internet Explorer иKonqueror (последний, впрочем,уже исправился) в равной мере от-носится и к другому продукту, ис-пользующему тот же engine - MSOutlook.

Отсутствие каких-либо предуп-реждений о несоответствии серти-фиката (который, в принципе, ва-лидный, но принадлежит другому),позволяет относительно легко под-делывать цифровые подписи подсообщениями. Если Microsoft в бли-жайшее время серьезно не займет-ся этой проблемой, следует ожи-дать взрыва злоупотреблений наэтой почве, ведь с использовани-ем этой уязвимости уже написанаспециальная программа - sslsniff,которая живет по адресу http://www.thoughtcrime.org/ie.html.

ht tp://www.theregister.co.uk/content/55/26924.html ]

Украина переходит насвободные программы

15 августа на рассмотрениеВерховной Рады Украины поданпроект Закона «Об использова-нии Открытого (Свободного) про-граммного обеспечения в госу-дарственных учреждениях и в го-сударственном секторе хозяй-ствования». Все госучреждения иучреждения и предприятия госу-дарственного сектора народногохозяйства должны использоватьтолько «открытое» ПО, под кото-рым имеются в виду программы cоткрытым исходным кодом, рас-пространяемые по лицензии GPL,а также по лицензиям типаApache или BSD. Использованиекоммерческого программногообеспечения допускается тольков исключительных случаях и в по-рядке, изложенном в ст. 6 зако-нопроекта. При этом, одним изобязательных требований являет-ся способность данного про-граммного обеспечения сохра-нять информацию в свободных(открытых) форматах.

Забавно, но при этом самтекст законопроекта [ht tp://o rac le2 . rada.gov .ua /p ls /zweb/w e b p r o c 3 4 ? i d = & p f 3 5 1 1 =12883&pf35401=23268 ] набран вMS Word.

Источник: Верховная Рада Ук-раины [http://oracle2.rada.gov.ua/pls/zweb/webproc34?id=&pf3511=12883&pf35401=23268 ]

Новая программа: ogle -DVD проигрыватель(GPL) для Solaris, Linux иBSD

Проигрыватель DVD видеодис-ков с поддержкой DVD-меню, по-зволяет проигрывать криптованыеDVD диски, возможность произво-дить скриншоты, реализована воз-можность поиска. Поддерживае-мые форматы: AC-3, MPEG[2],LPCM.

ht tp://www.dtek.chalmers.se/groups/dvd/

Обновлен стандартбезопасности

Впервые за последние 10 лет былподвергнут серьезному пересмотрустандарт безопасности, разработан-ный Организацией по Экономичес-кому Сотрудничеству и Развитию(Organisation for EconomicCooperation and Development, OECD).В новом варианте 7799 много вни-мания уделено вопросам обучения иизначальной интеграции процедурбезопасности в информационные си-стемы, а также оценке рисков.Jeremy Ward, представительConfederation of British Industry (CBI)назвал новый документ «зеленымсветом на информационной супер-магистрали». Что же, надо почитать,чего там такого революционного.

Источник: vnunet [ http://www.vnunet.com/News/1134825 ]

овая программа:mod_samoylyk - модульдля динамическогоконфигурированиявиртуальных хостов

Модуль для переадресации вир-туальных хостов с возможностьюустановки uid и gid пользователя дляsuexec (примерно cgiwrap + suexec= mod_samoylyk). Описание пользо-вательских хостов находятся в не-зависимой базе, при добавленииили изменении виртуального хостаперезапуск apache не требуется,каждый виртуальный хост исполь-зует примерно 0,3 кб памяти(VirtualHost в apache сьедает 10,5 кб)

Качать отсюда http://w w w . s a m o y l y k . c o m / m o d u l e s /mod_samoylyk.tar.gz

Microsoft латает дырку вSSL

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

Источник: Microsoft [http://www.microsoft.com/technet/treeview/default.asp?url=/technet/security/bulletin/MS02-050.asp ]

Linux на SmatrPhoneLinux портирован на SmatrPhone

китайской компанией CMS. Причемэто вполне законченный коммер-ческий продукт.

h t t p : / / l i n u x w o r l d . c o m . a u /news.php3?nid=1797&tid=1nY

Page 7: 001 Системный Администратор 10 2002

5№1, октябрь 2002

тенденции

Опасные игрыЗакон, принятый правитель-

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

Можно попасть в тюрьму заубийство... монстра в видеоигре.

Источник: Zdnet.ru [ http://zdnet.ru/?ID=287110 ]

Microsoft IIS6: веб-сервер строгого режима

Проектируя IIS6, разработчикииз Microsoft действовали самоот-верженно.

Философией софтверного ги-ганта всегда было создание про-дуктов, максимально доступных,максимально «скриптабельных» имаксимально мощных. Теперь всене так. После двух лет нападок состороны секьюрити- консультантови интернет-вандалов разработчикиMicrosoft решили, что, когда делокасается интернета, лучшая частьотваги — это осторожность. Теперьони думают лишь о том, как поме-шать пользователям добраться доразных функций.

Установка и настройкаLinux на ноутбуке

В руководстве по установке RedHat 7.3 на ноутбуке CompaqPresario 711CL затрагиваются та-кие моменты как настройка ACPIподсистемы управления питанием,мониторинг уровня заряда батарей,настройка звука и подключениеUSB устройств.

ht tp: / /www.l inuxjournal.com/article.php?sid=6291&mode=thread&order=0Ao

Linux постепенноотвоевывает позиции ...

Если верить статье, то все боль-ше IT специалистов подумывают опереводе серверов на Linux. 31 про-цент перевел сервера с Windows,24 — c других Unix и 14 — с другихоперационных систем.

Правда, 46 процентов пока невладеют серверами на основе Linuxили не собираются переводить —так что есть куда расти.

http://news.com.com/2100-1001-956496.html?tag=fd_topM

Регулярные выраженияв Perl 6Продолжение серии статей, посвя-

щенных технологиям Perl 6, цель дан-ной статьи - знакомство с новыми воз-можностями построения регулярныхвыражений (regex).

http://www.perl.com/pub/a/2002/08/22/exegesis5.html

Wine Tools -Wine Tools 1.13

Вышла новая версия WineTools — Wine Tools 1.13. Даннаяпрограмма (или скорее набор про-грамм) умеет:—Инсталлировать приложения.—Деинсталлировать их.—Создавать виртуальный

Windows диск.—Редактировать конфигурацион-

ный файл Wine.http://www.franksworld.net/wine/

winetools/s

MPlayer 0.90-pre7Удален старый код вроде

libvo2, подчищен libmpcodecs, до-бавлена поддержка аудио-кодекаsipr и поддержка realvideo, сдела-ны новые фильтры, переписан ви-деозахват и многое другое.

h t t p : / / w w w . m p l ay e r h q . h u /homepage

Network Associatesкупила разработчика«трояна» DragNet

После улаживания финансово-го вопроса с акционерамиMcAfee.com по возвращению конт-роля, калифорнийская компаниясетевой безопасности NetworkAssociates заявила о приобретенииTraxess Inc. из штата Юта.

Основной продукт Traxess —«DragNet» - программа, которая от-сылает и воспроизводит нажатияклавиш с одного компьютера надругой. Идея программы-шпионасостоит в контроле действий со-трудников со стороны службы бе-зопасности компании. Программапредназначена для работы в гига-битных сетях и использует запатен-тованные технологии, позволяю-щие «шпиону» загружать вторуюкопию файлов вплоть до большихMP3-файлов или потокового видео,чтобы можно было увидеть, какименно неправильно сотрудник ис-пользует рабочий компьютер.Председатель Traxess говорит, чтоон рад передать продукт, создава-шийся годами, в такие надежные и,главное, популярные руки, какNetwork Associates.

Network Associates тоже преус-пела в создании аналогичных про-грамм, среди которых - платформаSniffer («Нюхач» — термин, обозна-чающий программу перехвата тра-фика), а точнее — Архитектура Уп-равления Корпоративным Сниф-фером — для работы с любыми ви-дами трафика в высокоскоростныхсетях.

Новая программа:ScanDoc - построениедокументации черезсканирование C++исходников

Программа позволяет проскани-ровать исходники на C++ и постро-ить основываясь на комментарияхвнутри исходников проиндексиро-ванную документацию для функцийи блоков сканируемой программы.

http://scandoc.sourceforge.net/

Ряд статей для людей,использующих ОС AIX

Журнал SysAdmin Magazine от-крыл online доступ к некоторым ин-тересным статьям по OC AIX опуб-ликованным в 2001 году.

http://www.samag.com/articles/2001/0106/supplement/

Page 8: 001 Системный Администратор 10 2002

6

FAQ PERL

Как мне получитьзашифрованныйпароль?

Стандартной функцией crypt(),например вот так:

�� ��������� ���� ����� � �� ����������� �

��������� ����� ��� � � � � � � � � � � ! " # $ % & ' ( ) * + , - . / 0�1�2�34�56�7� �8����9:�;<=>?@ABCDEF�G

�1�3�H����I�����2JKG��L�%��������J���2JL�������KKG��L�%��>������J���2JL�������KKG������ 5 ��JM��L������NL�%��O�L������NL�%��>OKGP

L�����2H��92� ������JL�����H��92�3�H���JKKG

�������G�8���� Q�������F�4RG

��STUVWVXYZXV[\�]^U_�]`�^\`YaVWZbL�$,I&�*�P� �� Q�1��c����1��RG

��dZTU`�eYf�]gZh`YVL<�i7�2�7 �iG

��jUe[Yf[\Tf�`U�g`eZU[Yf� �6JK�kk�:��G

��jUhYbaV[\Tf�`U�U[g\ZWVYV�� � )*�%+*G� �� � )*��((G� ��

)*��$G

��l[YV[\�h`g[W_�U[h^mZ\�hVUVY`n`\�42���Q�RG

�� o`peV[\� W`X^b� T[TTZb� Z� TUVW`XZ\TfYZe[g`\

��ng^]]q�]g`r[TT`X��aU`s�WVT�TY^aVtW`W[�]gZsZYZ

�����Jk)/)H��2KG

��u[g[vXVUqXV[\�TZnWVYq��eYf�h`gg[hwUW`n`�Xqv`eV

L)��IQ�$*RP� �� L)��IQ'+�*RP� �L)��IQ*�(#RP���Q8���RG

L)��IQ�+&RP���Q�3� �RG

��l[YV[\�WVxZ�U[\Wq[�e[YVFFF

��yqv`eZ\8���JKG

�1�8����I����u`\[zV[\�TbeV�h`e�eYf�h`gg[hUW`n`����]g[hgVz[WZf�gVs`Uq���FFF��:��J<KGP

Как сделать так, чтобыскрипт работал вфоновом режиме, какдемон?

Варианта два. Первый - восполь-зоваться модулем Proc::Daemon,второй — сделать все самому, при-мерно так:

Если Вы хотите написать демо-на, реализующего работу черезсеть, рекомендуем ознакомиться смодулем Net::Daemon.

��� J�����JL���2H��92��1�JL�����2H��92�<�>KK��8�L�����2H��92K�I��uVg`Y_�X[g[WP���I��uVg`Y_�W[�X[g[WP

А как мне проверитьсоответствиевведенного паролязашифрованному?

Первых два символа пароля со-джержат шифровальный ключ.Если, взяв их, зашифровать прове-ряемый пароль, то зашифрованныестроки должны совпасть. Пример:

L��2���� �� Q���������7�2�7 �F��2RG

���Jw�L��2���K�I�����4�����2�������4���1����� �

� ��2�1�2�21��� 9��7��L7��������H��7JL<KG������J ��J&����"��L��2���KK�I������� �2��3� ��� ������1���

�����i����2� �2&������:���=G��P��7��L �2��2�{&����"�|G���� �&����"�G� � �� � ��� �4�� �� �� �� �� 9��4

��4���2�����JL �2��2�|�=�kk�6���J<�L �2��2KK

I� � � � �� �� �4�� �� ��� �� ������3

����2�����:���=G��P���I�������4����� ����� �3�2�2��PP

��9������2���� ���J&����M|L��2����K� ��2�G������&���LLG�� J&��KG

��2 � 7�9 �6FFF

���7 ����2���������6� L��2���G:��J<KG

��7�6���� �6L� �6�����7����7��7�2�7 �F� �6�G���� J ��

J"%�!��"���|L� �6�����7�KK� I��2��M���� �� ���� �6����}��GP���� J�� �6

J"%�!��"��"%�!H�.~"%�!H$�KKI� � ������ M7�� � ��� �� ����2�

������3}��G��:��J<KGP

��2 � 7�9 �6FFF

����� �6�� �6������ J"%�!��"�KG�����6JL� �6�����7KG

Как сделать так, чтобыпрограммагарантированноработала только в одномэкземпляре?

Способ первый, принятый вмире Unix:

Способ второй, основанный наблокировании файлов:

по материалам www.xpoint.ruсоставил Дмитрий Горяинов

Чем отличаетсясинтаксис скриптов наUNIX и WIN платформах?

Юниксовые скрипты плохо вос-принимает досовский перевод стро-ки — CR LF. Если открыть такойфайл в vi в конце строк будут ^M.Удалить их можно, например такимскриптом:

���1���1�4�������w2�w7�<CCA� ��3���L=� ��3�L=F ��3FQ2�����7w�2w��F�#Q2�w�M��#��3��L=�| 7��w�� �L=

Как защитить моюпрограмму, чтобы никтоне смог её прочитать?

Perl-сценарий представляет со-бой открыто распространяемыйкод.

Page 9: 001 Системный Администратор 10 2002

АДМИНИСТРИРОВАНИЕ

Page 10: 001 Системный Администратор 10 2002

8

администрирование

В данной статье я буду преимуще-ственно говорить о версии 12.0.x.(отличия версий, в основном, в веб-интерфейсе и поддержке тех илииных технологий). На каждый изкоммутаторов может быть установ-лено программное обеспечениестандартного (Standard Edition) ирасширенного типа (EnterpriseEdition).

В enterprise edition входят: под-держка магистралей 802.1Q, прото-кол TACACS+ для единой авториза-ции на свитчах, модифицированнаятехнология ускоренного выбораSpanning Tree (Cisco Uplink Fast) идр. Здесь я преимущественно будуописывать настройку свитчей с по-мощью интерфейса командной стро-ки (CLI). Данные свитчи предостав-ляют множество сервисных возмож-ностей. Кроме этого, они идеальноподходят для крупных сетей, так какимеют высокую пропускную способ-ность — до 3-х миллионов пакетовв секунду, большие таблицы адре-

сов (ARP cache) — 2048 mac адре-сов для Catalyst 2900XL и 8192 дляCatalyst 3500, поддерживают клас-теризацию и виртуальные сети(VLAN), предоставляют аппаратнуюбезопасность портов (к порту можетбыть подключено только устройствос определённым mac адресом), под-держивают протокол SNMP для уп-равления, используют удалённое уп-равление через веб-интерфейс ичерез командную строку (т.е. черезtelnet или модемный порт). Кромеэтого, имеется возможность монито-ринга портов, т.е. трафик с одногопорта (или портов) отслеживаетсяна другом. Многим покажется полез-ной возможность ограничивать ши-роковещательный трафик на портах,предотвращая тем самым чрезмер-ную загрузку сети подобными паке-тами. Исходя из всего этого, можноутверждать, что выбор свитчейCisco Catalyst является идеальнымдля крупных и средних сетей, так какнесмотря на высокую стоимость

(>1500$), они предлагают широкийвыбор сервисных функций и обеспе-чивают хорошую пропускную спо-собность. Наиболее привлекатель-ными возможностями данных свит-чей являются: организация вирту-альных сетей (в дальнейшем VLAN),полностью изолированных друг отдруга, но синхронизированных меж-ду свитчами в сети, и возможностькластеризации для единого входа всистему управления свитчами и на-глядного изображения топологиисети (для веб-интерфейса). Перс-пективным является использованиемногопортового свитча в качествецентрального элемента сети (в звез-дообразной архитектуре). Хотя свит-чи поставляются с подробной доку-ментацией, но она вся на английс-ком языке и нередко не сообщаетнекоторых вещей, а иногда, напро-тив, бывает слишком избыточной.Для начала хотел бы рассказать опервоначальной настройке свитча.Итак, Quick Start.

УСТАНОВКА И НАСТРОЙКАКОММУТАТОРОВ CISCO CATALYST СЕРИЙ2900XL И 3500

ХЕВИ ХАРДВЭРИнтеллектуальные свитчи (по-русски коммутаторы) CiscoCatalyst серий 2900XL и 3500предназначены для крупныхкорпоративных сетей. Онипредставляют собой коммутаторывысокого класса смикропроцессорнымуправлением, флэш-памятью,объёмом 4 Мб и DRAM-памятьюобъёмом 8мб. На данныхустройствах обычно установленаспециализированнаяоперационная система Cisco IOS.

ВСЕВОЛОД СТАХОВ

Page 11: 001 Системный Администратор 10 2002

9№1, октябрь 2002

администрирование

� Подключите поставляемый плос-кий провод в разъём на задней па-нели коммутатора с маркойconsole.

� Подключите другой конец кабеляк com-порту компьютера через со-ответствующий переходник и запу-стите программу-эмулятор терми-нала (например, HyperTerminal илиZOC).Порт консоли имеет следующие

характеристики:� а) 9600 бод;� b) Нет чётности;� c) 8 бит данных;� d) 1 бит остановки.

Важное замечание для кластера(объединения нескольких коммутато-ров): если вы хотите использоватькоммутатор в качестве члена класте-ра, то можно не присваивать ему IPадрес и не запускать построитель кла-стера. В случае командного свитча,вам необходимо выполнить следую-щий пункт.� Присвоение IP коммутатору

В первый раз, когда вы запускае-те свитч, то он запрашивает IP адрес.Если вы назначаете ему оный, чтовесьма желательно, то он может кон-фигурироваться через Telnet.

Необходимыетребования к IP

Перед установкой необходимознать следующую информацию осети:� IP адрес свитча.� Маска подсети.� Шлюз по умолчанию (его может и

не быть).� Ну и пароль для свитча (хотя, ско-

рее всего лучше это придумать са-мому).

Первый запуск

Выполняйте следующие действиядля присвоения коммутатору IP адре-са:

Шаг 1. Нажмите Y при первой под-сказке системы:

Шаг 2. Введите IP адрес:

Шаг 3. Введите маску подсети инажмите Enter:

Шаг 4. Введите, есть ли у васшлюз по умолчанию N/Y, если есть,то наберите его IP адрес после нажа-тия Y:

Шаг 5. Введите IP адрес шлюза:

Шаг 6. Введите имя хоста комму-татора:

Шаг 7. Введите пароль. Кроме это-го, затем на вопрос о пароле дляTelnet ответьте Y и введите пароль длядоступа через Telnet, так как иначевозможны странности работы с telnet.У меня, к примеру, подключениеTelnet к свитчу обрывалось по причи-не: пароль нужен, но не определён:

Создался следующий файл конфи-гурации:

Шаг 8. Если всё нормально - жми-те Y; нет - N (только учтите, что па-роль хранится в зашифрованномвиде).

Открытие Cisco VisualSwitch Manager Software

После того, как вы присвоили IPкоммутатору, то вы можете конфигу-

рировать его через веб-интерфейс спомощью Cisco Visual Switch или че-рез консоль (Telnet или модемныйпорт). Выбор средства настройки —ваш выбор, но учтите, что веб-интер-фейс обладает сильной «тормознуто-стью», так как основан целиком наапплетах Java (не забудьте включитьподдержку Java в браузере). Кромеэтого Cisco Visual Switch работаеттолько в браузерах Microsoft IE иNetscape (хотя у меня в Netscape 6.0ничего не работало). К достоинствамэтого типа настройки можно отнестинаглядность, простоту и возможностьполучить помощь по всем пунктам.Интерфейс командной строки являет-ся немного сложным для тех, кто ред-ко работает с консолью, но настрой-ка через командную строку являетсяочень быстрой и предоставляет до-полнительные возможности. Альтер-нативным способом настройки явля-ется веб-консоль. В ней показывают-ся в виде гиперссылок допустимыекоманды CLI, и вы можете собратьнужную последовательность командкак бы из кирпичиков.

Далее, можно настроить VLAN,вообще термин VLAN — виртуальнаялокальная сеть. Такая сеть отличает-ся от физической LAN лишь тем, чтоорганизуется разделение пакетов вединой локальной сети так, как еслибы это были разные подсети. Такимобразом, с помощью VLAN можноорганизовать деление локальнойсети на отдельные участки. При этомсуществует возможность регулиро-вать взаимодействие VLAN весьмашироко.

Типы VLAN

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

Присоединениеконсольного кабеля

��������������

������ ���� ����� ��� ������ � ������������������������� ��

�����������������������������

��������������

������������������

������� ������������

��������� �� !"�#��������"$%&"'&("&%)�%**&%**&(&(�#� ������+������ "$%&"'&("&("������ ������� *� ,",-.#/,�0� ���1.2

'3�42��#���������#��5�������#���������#�����������

6��������������������������2���

3�������� ����� ������������� ����������2��� ��

���������������

Page 12: 001 Системный Администратор 10 2002

10

администрирование

VLAN (при этом необязательно, что-бы они были на том же свитче). Приэтом абсолютно исключается возмож-ность взаимодействия с «чужим» пор-том. А сами коммутаторы соединяют-ся между собой посредством особыхканалов связи - trunk магистралей. Потаким магистралям проходят данныевсех VLAN. Но, к сожалению, trunkпорт должен быть point-to-point (о двухконцах) и может подключаться толь-ко к свитчам и роутерам, поддержи-вающим VLAN, так как к пакету до-бавляется 4-х байтный тег, содержа-щий информацию о VLAN и её при-оритете. Таким образом, организациясетевого доменного сервера стано-вится возможной только при исполь-зовании роутера. Но сейчас есть вы-ход в использовании ОС Linux, кото-рая поддерживает данный протоколна уровне драйвера ядра, VLAN фи-гурируют в качестве виртуальных се-тевых устройств. Здесь нужно толькоуказать правильный тип инкапсуляциипакетов - IEEE 802.1q (по умолчаниюиспользуется тип ISL). При этом, есливсе VLAN находятся в одной подсети,то маршрутизация будет проходитьтолько на уровне статических путей.Данной теме посвящено достаточноеколичество документации, и пакет

vlan-utils присутствует во многих со-временных дистрибутивах Linux(Mandrake и ALT Linux). С ядра 2.4.9опция компиляции CONFIGURE_802Qприсутствует на странице NET как эк-спериментальная, поэтому вы долж-ны поставить соответствующую оп-цию CONFIGURE_EXPERIMENTAL(вядрах 2.5 эта опция уже не экспери-ментальная), затем make dep —>make bzImage. Настройка VLAN состороны Linux тоже не должна вызы-вать трудностей. Для настройки слу-жит утилита vconfig из пакета vlan-utils. Для получения этой утилиты, атакже патчей для ядра откройте http://scry.wanfear.com/~greear/vlan.html.Патч для ядра описан в FAQ на дан-ной странице, я же ограничусь приме-ром настройки 2 VLAN на Linux маши-не:

Включаем интерфейс физическойсетевой карты, но без IP адреса (в до-кументации сказано, что если у реаль-ной сетевой карты есть IP адрес, то vlanработать не будут, но у меня это про-шло без особых проблем, главное, что-бы все сетевые устройсва были в РАЗ-НЫХ ПОДСЕТЯХ, причём это касаетсяи виртуальных LAN, иначе вообще ни-чего работать не будет — проверял):

Каждый VLAN добавим на нужныйинтерфейс (не добавляйте VLAN поумолчанию, так как пакеты этого VLANидут без инкапсуляции):

Всё, мы прописали VLAN’ы, кото-рые будут использоваться на интер-фейсе, нужно присваивать им Ip ад-реса (тип имени см. выше) в разныхподсетях:

7�5�������������(�%7�5�������������(�.

7����������+7� ��������� +�� 5��(((%� "8%&"'4&%&"

�������� "8%&"'4&%&%**� �����%**&%**&%**&(� �#

7� ��������� +�� 5��(((.� "8%&"'4&.&"�������� "8%&"'4&.&%**� �����%**&%**&%**&(� �#

9:;;<=>?@:AA>B�C@A>�4&4�DE@=2FGHIH:J:F=K� H:;;<=>?@@� ')+E>L=:MNO� P>+

HG=:M3������%8*(+"% �"&4�QP>HG=2FGH3������%8*(+%) �.&'�QP>HG=2FGH3������%8*(R+%) �'&'�QP>HG=2FGH3������%8*(3+%) �.&8�QP>HG=2FGHQ>HF@;>SKA>B�FH:J:F=K�H:;;<=>?@@�)&)

DE@=2FGH4�-E>L=A>B�J>FPJGTGSGAA>B�>JO@=GH=<+

J>�P>;B=@�TSB�MFGOP:J=:M"'�-E>L=�U1 -�@�4�-V>L=�WSXC�P>;B=KY:TTGJZH>�4["8%�- 3�>TJGF:M

I=>AT>J=N����� 4(%&"\� ��##���� ]#������ ������

�������� ��##���^����� 4(%&.\� ����� ��#��\� ��� "(_��R[

"((_��R0[���"(((_��R� #���������4(%&"U�/#�����+R�����������������4(%&"#�3�/�����4(%&"`��� !�����4(%&.��"(((_��R��#���������������4(%&.��"((_��R0��#���������������4(%&.�"(_��R��#����������

a>AANG�MbB=N�F�F>L=>��&��

Технические параметрыПроизводительность

5������� ���c��c��#�� ���+��#��� +=@P�A>@;GA:M>A@B�M@J=<>SKANO�<F=J:LF=M[;:ZG=�PJ@A@;>=K�FSGT<de@G�bA>fGA@B

�� !c��6/c��U@;B�<F=J:LF=M>��E<TG=�MNgSBTG=K�=>H

5��(((*�� !c��6/c��Uc!hc� U@;B� <F=J:LF=M>� E<TG=� MNgSBTG=K� =>H

5��*U��c��6/c��U@;B� <F=J:LF=M>� E<TG=� MNgSBTG=K� =>H

���(&(((*

U��c��6/c��Uc!hc� U]P:� <;:Sf>A@d^@;B� <F=J:LF=M>� E<TG=� MNgSBTG=K� =>H

���(&*

7�������������(�(&(&(&(��#

Page 13: 001 Системный Администратор 10 2002

11№1, октябрь 2002

администрирование

Если вы планируете использоватьмаршрутизацию в сети, то добавьтеследующее:

Для удаления VLAN используйтесинтаксис:

Подобные скрипты удобно пропи-сать в файле /etc/init.d/network.

Кстати, учтите, что MTU в trunkмагистралях не 1500, а 1504 из-затого самого тега.

Trunk магистрали поддерживаютсявсеми типами свитчей, которые умеютделать VLAN. Другое преимущество -использование особого протоколаCISCO, обеспечивающего централизо-ванное управление всей системойVLAN - VTP (vlan trunk protokol). Напри-мер, вы можете на сервере VTP отклю-чить или включить определённую VLAN.Широковещательный трафик по умол-чанию не распространяется междуVLAN. MultiVLAN очень интересный типорганизации VLAN. Он состоит в опре-делении для порта нескольких допусти-мых VLAN (например, для экономистовэто могут быть VLAN Economics и Serverдля доступа к общим серверам и.т.д.).Такой тип подходит для организациисети с помощью одного центральногоCatalyst свитча и нескольких другихсвитчей или хабов, к нему подключён-ных. Общий сервер также должен под-ключаться к центральному Catalystсвитчу к multiVLAN порту для общениясо всеми рабочими станциями. Широ-ковещательные же пакеты будут рас-пространяться по всей сети (разумновключить фильтры шторма). Но привыборе типа VLAN, учтите, что на од-ном свитче не может быть разных ти-пов организации VLAN, из-за особен-ности протоколов (невозможна синхро-низация внутреннего формата VLANпакетов и trunk магистралей, т.к. в пос-ледних можно указывать лишь одинномер VLAN). Ни в коем случае не со-единяйте свитчи Catalyst multiVLAN пор-тами, т.к. это приведёт к тому, что дру-гой свитч, получивший пакет сmultiVLAN порта, не сможет определитьк какому VLAN он относится и присво-ит ему VLAN по умолчанию (1 VLAN).

Итак, вы подсоединили нуль-мо-демный кабель или запустили сеансtelnet. Во-первых, на приглашениеHOST_NAME> надо ответить enableи ввести пароль к свитчу для полу-чения доступа к конфигурации. Дляпросмотра сведений о свитче набе-рите show running-config. Подсказкапо интерфейсу CLI. Здесь есть такиеудобства как автодополнение кноп-кой TAB — наберите начало коман-ды, например show ru<TAB>, и онорасширится в show running-config.Можно в любой момент получитьсправку по любому вопросу: простонажмите ? и вам будут предложенывозможные параметры команды, на-пример, show ?. Для повторения пре-дыдущих или следующих командможно использовать курсоры вверхили вниз. Для пролистывания текстапри запросе —more— нажимайтепробел для опускания текста вниз настроку. Итак, вы набрали showrunning-config, после этого отобразит-ся информация о текущих настрой-ках. Вначале общая информация освитче (адрес, имя, адреса шлюзи.т.д.), а затем информация о портах.Здесь особое внимание я бы хотелобратить на информацию о режимеVLAN порта: switchport mode %%%%.

Следующий параметр switchport по-казывает особые параметры для дан-ного типа порта. Например для accessэто единственный идентификаторVLAN, для multi - список допустимыхVLAN, разделённых «,» или «—» дляуказания промежутка VLAN. Таким об-

разом, после сделанных измененийнеплохо было бы смотреть, что имен-но произошло.

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

Если вы забыли пароль, то делоещё хуже. Для смены пароля нужно:� Выключить питание свитча.� Подсоединить нуль-модемный ка-

бель.� При включении питания удержи-

вать кнопку mode.� При появившейся подсказке на-

брать flash_init (инициализацияфайловой системы).

� rename flash:config.text flash:ДРУГОЕ_ИМЯ.text

� Перезагрузите свитч.

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

Вы сразу же приступите к началь-ному конфигурационному диалогу.Для выхода из вложенных режимов

7� ����� "� i� 2#���2���2���2�#5)2�#c������

7�5����������5��(((%

������+�JGZ@;�F=>=@fGFH:L��� !j-�����+�;<SK=@�� !�P:J=jR�����+�JGZ@;�������;>g@F=J>S@jU�����+���-/�JGZ@;&

i�����7����� ���� ������&��\�

���� aklDmncoQp&��\�7�����

Page 14: 001 Системный Администратор 10 2002

12

администрирование

конфигурации нажимайте exit. Дляполного выхода наберите два разаexit. Итак, приступим к настройкеVLAN. Предполагаю, что вы уже на-ходитесь в режиме конфигурации:

Теперь вам доступны любые дос-тупные изменения конфигурации пор-та. Наименование порта происходитпо следующей схеме:� Тип порта (FastEthernet (100 Мб),

Ethernet (10 Мб), Gigabit (1 Гб)).� Номер модуля (0 для встроенных

портов и далее 1, 2, 3 для допол-нительных модулей).

� Номер порта в модуле.Для получения списка допустимых

команд, как обычно, можно нажать ?.Подробнее остановлюсь на командеswitchport mode, определяющей ре-жим работы порта для VLAN. Допус-тимые значения access (статическийдоступ), multi (мультидоступ) и trunk(режим туннельной магистрали). Дляконфигурации конкретного режиманужно применять:

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

Не забудьте посмотреть результа-ты вашей работы:

Для осмысленной настройки VLANможно использовать базу данных VLAN:

Далее можно поменять настройкиконкретной VLAN:

Например, name - настройка именидля данной vlan. Довольно удобно да-вать VLAN осмысленные имена, но нуж-но иметь в виду, что если на разныхсвитчах одни и те же vlan будут иметьразные имена, то это может вызватьпутаницу в дальнейшем обслуживании.

VTP — протокол trunk магистра-лей — позволяет централизовать уп-равление vlan с сервера VTP. Инфор-мация от сервера распространяетсяк клиентам через trunk магистрали.В ней содержится полная информа-ция о VLAN, сконфигурированных насервере. Клиент, в соответствии сэтой конфигурацией, выполняет син-хронизацию своей конфигурации.

Для настройки VTP в режим сер-вера выполните следующее:� В основном режиме войдите в раз-

дел конфигурации VLAN.

� Введите имя домена VTP(1 — 32символов).

� (Необязательно) Установите па-роль для домена(1-64 символа).

� Установите нужный режим VTPдля данного свитча (клиент/сер-вер).

� Возвращаемся в основной режим.

� Проверяем настройки VTP.

Пример настройки VTP сервера:

]������^7����������q�����������\2\]A<ZANL� M>;� P:J=^[� b>=G;� MN� M� JGZ@;GH:AW@g<J>?@@�P:J=>�+�]������+��^7

������#����������5����U�+�GT@AF=MGA+A>B�5��

������#���������5����U[��U[��U�@S@������#���������5����U+�U[��U+�U[��U+�FP@F:H�T:P<F=@;NO�5��

������#�����������������5�����/R�U+�T:P<F=@;NG�TSB�;>g@F=J>S@�5��]P:�<;:S+f>A@d�"+"((*^

� #�������� 5��� ��/R�U� +� W@SK=J>?@BC@J:H:MGe>=GSKA:g:�=J>W@H>�;GZT<�5��

����#��������+�=@P�P>HG=>]�����@S@���"r�+������4(%&"r^

����5��5����U�+�TSB�������;>g@F=J>+S@�=@P>������4(%&"r�A:;GJ�5��[�TSB�H:+=:J:L� AG� @b;GABG=FB� W:J;>=� P>HG=>� ]P:<;:Sf>A@d�"�5��^

���������#���������5���&&&���������#������������

]������+��^7�\��]������^7�\��7����� �������+������7������ ����� +� GFS@� A>T:� b>P@F>=K

A>F=J:LH@

75��������]5��^7]5��^7����� +� TSB� P:H>b>� F:F=:BA@B

5���A>�T>AA:;�FM@=fG

]5��^75����U���+�FP@F:H�M:b;:Z+ANO�A>F=J:GH

7�5��������]5��^7�5�#������ 5����lF=>A:MH>�@;GA@�T:;GA>� 5����]5��^7�5�#������ 5�����#�������� � lF=>A:MH>�P>J:SB�TSB�T>AA:g:�T:;GA>&]5��^7�5�#����5��sHSdfGA@G�JGZ@;>��R��FGJMGJ>&]5��^7��\��t>F=J:LH@� PJ@;GAGAN&sNO:T@;&&&&

7������5�#�������R������������������������������ �%3������������1�5��������������� �(-\����� !����##������������� �'4!���������\��������� !��������� �'

�����5�#������

5��������

�\��

Семействакоммутаторов CiscoCatalyst 2900XL/3500XL

Семейство коммутаторов 2-гоуровня Catalyst 2900XL представле-но пятью различными моделями:1) WS-C2912-XL — содержит 12

универсальных портов 10/100Mbps Ethernet с автоматическимопределением скорости и режи-ма передачи;

2) WS-C2924-XL — содержит 24

5�#����������+��

5�#� ���5��]������^

5�#�#�������#������+5���

Page 15: 001 Системный Администратор 10 2002

13№1, октябрь 2002

администрирование

универсальных порта 10/100Mbps Ethernet с автоматическимопределением скорости и режи-ма передачи;

3) WS-C2924M-XL — содержит 24универсальных порта 10/100Mbps Ethernet с автоматическимопределением скорости и режи-ма передачи, а также два слотадля установки дополнительныхинтерфейсных карт;

4) WS-C2924С-XL — содержит 22универсальных порта 10/100Mbps Ethernet с автоматическимопределением скорости и режи-ма передачи, а также два опти-ческих порта 100 Mbps FastEthernet;

5) WS-C2912MF-XL — содержит 12оптических портов 100 MbpsEthernet, а также два слота дляустановки дополнительных ин-терфейсных карт.

В состав семейства коммутато-ров Catalyst 3500XL входит три мо-дели:1) WS-C3512-XL — содержит 12

универсальных портов 10/100Mbps Ethernet с автоматическимопределением скорости и режи-ма передачи, а также два портаGigabit Ethernet;

2) WS-C3524-XL — содержит 24универсальных порта 10/100Mbps Ethernet с автоматическимопределением скорости и режи-ма передачи, а также два портаGigabit Ethernet;

3) WS-C3508G-XL — содержит 8портов Gigabit Ethernet.

Коммутаторы этих семействпредназначены для работы в каче-стве сетевого оборудования рабо-чих групп среднего и малого разме-ра и имеют для своего класса оченьвысокую производительность — до3-х миллионов пакетов в секунду, ко-торая обеспечивается мощным мо-дулем коммутации архитектуройкоммутатора, использующей разде-ляемую память, беспрецендентныемеханизмы управления и контроляза работой устройства и т.п. Высо-кая производительность серии2900XL подтверждена в серии испы-таний таких тестовых лабораторийкак Mier, ZDnet и др.

Коммутаторы семейств 2900XL,3500XL, а также Catalyst 1900/2820могут объединяться в стеки (до 16устройств) при помощи соединенийFast Ethernet, Fast EtherChannel (аг-грегирование Fast Ethernet по 2 или4 канала), а также Gigabit Ethernet иGigabit EtherChannel. Максимальноеколичество портов, которое можетбыть установлено в одном стеке рав-но 380. Такой стек является единымобъектом сетевого управления, ко-торое может выполняться как припомощи командного языка CLI с кон-соли или при помощи протоколаtelnet, так и при помощи специали-зированных систем управления типаCWSI (Cisco Works for SwitchedInternetworks), так и при помощиWEB-технологии c любой рабочейстанции, оснащенной программамипросмотра Netscape или InternetExplorer.

Как и все коммутаторы, входя-щие в семейство Catalyst устройства2900/3500 обеспечивают построе-ние виртуальных сетей (в вариантепрограммного обеспеченияEnterprise), режим безопасности,при котором к коммутатору могутбыть подключены только станции суказанными MAC-адресами, 4 груп-пы RMON, специальный порт дляконтроля трафика, проходящего че-рез группу портов или в заданномVLANе и др.

Модульные модели коммутато-ров (WS-C2924M-XL, WS-C2912FM-XL) позволяют устанавливать допол-нительные 4-х портовые модули 10/100 Mbps Ethernet (витая пара), 2-хи 4-х портовые 100 Mbps Ethernet(оптика мультимод), однопортовыемодули Gigabit Ethernet (мультимод,мономод), а также однопортовыемодули ATM 155 Mbps (витая пара,мультимод, мономод). Мономодовыемодули для ATM и Gigabit Ethernetмогут быть выполнены в различныхвариантах дальности, при этом пре-дельная длина оптических каналовможет достигать 70 км. ТрансиверыGigabit Ethernet (GBIC — GigabitInterface Converter), устанавливае-мые в коммутаторах семействаCatalyst 3500XL, а также в соответ-ствующих модулях для коммутато-ров семейства Catalyst 2900XL явля-ются сменными, что позволяет гиб-

ко и эффективно конфигурироватькоммутаторы для подключения кканалам требуемого типа.

На каждый из коммутаторов мо-жет быть установлено программноеобеспечение стандартного (StandardEdit ion) и расширенного типа(Enterprise Edition). Расширенная ре-дакция дополнительно поддержива-ет транкинг (ISL/802.1Q), протоколTACACS+ для регламентации досту-па к коммутаторам, модифициро-ванную технологию ускоренного вы-бора Spanning Tree (Cisco UplinkFast) и др.

Техническиеспецификации

Производительность:1) 3.2 Gbps — коммутирующих мо-

дуль (для моделей Catalyst2900XL);

2) 10.0 Gbps — коммутирующих мо-дуль (для моделей Catalyst3500XL);

3) 3.0 million-pps пропускная спо-собность (64-х байтовые пакеты,Catalyst 2900XL);

4) 7.5 million-pps пропускная спо-собность (64-х байтовые пакеты,Catalyst 3500XL);

5) 4-MB разделяемая память;6) 8-MB DRAM and 4 MB Флэш-па-

мять;7) 2048 MAC-адресов (Catalyst

2900XL);8) 8192 MAC-адресов (Catalyst

3500XL).

Управление:SNMP Management Information

Base (MIB) II, SNMP MIB extensions,Bridging MIB (RFC 1493).

Поддерживаемые стандарты:1) IEEE 802.3x full duplex;2) IEEE 802.1D Spanning-Tree

Protocol;3) IEEE 802.1Q VLAN;4) IEEE 802.3z, IEEE 802.3x;5) IEEE 802.3u 100BaseTX and

100BaseFX specification;6) IEEE 802.3 10BaseT specification;7) IEEE 802.3z, IEEE 802.3x

1000BaseX specification;8) 1000BaseX (GBIC) —

1000BaseSX, 1000BaseLX/LH,1000BaseZX.

Page 16: 001 Системный Администратор 10 2002

14

администрирование

До сих пор возникает множество воп-росов по установке и настройке почто-вой системы на основе Postfix, Cyrus-SASL, MySQL, Courier-IMAP, Dr.Web,SquirrelMail.

Если использовать приведенныйниже опус в качестве банальной инструк-ции, у вас должна получиться легко мас-штабируемая и управляемая система, ко-торая без проблем — как со стороны ад-мина, так и со стороны железа — спо-койно будет тянуть по 5-10 тысяч почто-вых пользователей. При этом нет раз-ницы: сколько почтовых доменов заве-дено в системе, как называются пользо-ватели и так далее. Ибо с системнымиони никак не коррелируют.

Пользователи же получат стандар-тный набор сервисов: SMTP с аутенти-фикацией, pop и imap сервисы, доступк почте через браузер, плюс, чистую отвирусов почту.

Теперь оговорки. Данный текст на-писан в расчете на тех, кто уже пони-мает механизмы, происходящие внут-ри Linux. Если вы неделю как постави-ли Linux и желаете с помощью этого до-кумента поставить свой hotmail.com, тоя ни за что, как обычно, не отвечаю. Вселоги и прочее были взяты с моей рабо-чей системы. Я ничего не выдумывал ине придумывал — это все работает ре-ально.

В качестве базовой системы исполь-зовался RedHat 7.2. Но аналогично по-строенные системы работают и наRedHat6.2, и ASPLinux 7.2. Поэтому невижу причин, почему бы им не работать

на других системах. Все необходимыепрограммы и пакеты вы сможете найтив окрестностях freshmeat.net.

Если вы желаете задать мне воп-рос, задавайте по мылу:[email protected], но прежде прочтитехотя бы PostfixFAQ на www.postfix.org —ответы на 90% вопросов, на которые яне отвечаю, есть там. Еще одно усло-вие — сначала обдумайте и прочтитевсе сообщения системы в /var/log/messages и /var/log/maillog — обычнотам есть исчерпывающая информация,почему не работает что-либо.

Для нормальных: Просто мнеОЧЕНЬ надоели письма вида: «А чегооно не работает, когда я сделал все так,как ты написал?».

И последнее — специально для тех,кто задается вопросом: «Почему я выб-рал postfix? Ведь есть стандарт-де-фак-то sendmail. Есть еще exim,qmail и кучадругих почтовых серверов». Отвечаю:

— Sendmail я вынужден сразу ски-нуть со счетов. То, что описываетсяниже, sendmail не способен выполнить.Или способен, но с очень большими уси-лиями администратора системы. Я, по-чему-то органически не могу смотретьна творение djb. Ну а exim я просто невидел.

— Courier-IMAP выбран по другойпричине: где-то с полгода назад он ока-зался единственным IMAP сервером,который смог собраться на моей маши-не и работать под нагрузкой, не требуяк себе внимания.

— Dr.WEB — просто хороший анти-

вирус. Нет такой толпы глюков, на ко-торые бы я периодически не напары-вался, глядя на AVP. Тем более, что ондаже с тривиальной лицензией спокой-но выполняет работу почтового фильт-ра. Правда, с купленной лицензией бу-дет гораздо спокойнее — вирусы дажев архивах не пройдут. Но — если нетлицензии, то — нет.

— SquirrelMail — это просто един-ственная система Web-based почты, ко-торая не вызывает брезгливой реакциипри первом, главное, при последующихвзглядах. Плюс, она приемлемо рабо-тает с русским языком.

Теперь устанавливаем SASL. К со-жалению, установить его из RPM не по-лучится. Все, что я видел до этого, со-брано либо не так, либо не туда. В об-щем, неработоспособное. Но вы може-те попытать удачу.

Заберите патч для поддержкиMySQL и LDAP отсюда: http://www.surf.org.uk/downloads/sasl-1.5.27-ldap-ssl-filter-mysql-patch4.tgz.

Распакуйте полученный архив и по-ложите sasl-ldap+mysql.patch в кореньдерева исходников SASL.

Вот и все, патч установлен. Да-

������������� � � ���������������������� � � ���������

УДОБНАЯПОЧТОВАЯ СИСТЕМА

Итак, задача - завести почтовую систему, в которой вся информация опользователях, доменах и прочем лежала бы в базе данных. Зачем это нужно?Лично для меня это стало актуально после того, как в поддерживаемых мнойсистемах пользователи начали плодиться как кролики. Заводить на каждого свойаккаунт, смотреть, чтобы они не пересекались и не пользовались чужимидоменами и так далее. Наконец, мне все надоело и я решил сделать ЭТО.

ВЯЧЕСЛАВ КАЛОШИН

���������������� � ��������� �������������������������� ��������!���"�

Page 17: 001 Системный Администратор 10 2002

15№1, октябрь 2002

администрирование

вайте сконфигурируем SASL.

Соберем и установим его:

Устанавливаем методы аутенти-фикации:

Теперь пришла очередь postfix.Здесь ситуация та же. В принципе посети бродит много rpm, которые со-держат в себе откомпилированныйpostfix с поддержкой MySQL. Я пред-почитаю собрать его сам, и быть«чуть-чуть» уверенным в том, что язнаю, что собрал.

Следующие строчки — это однакоманда. Ее следует вводить в одинприем.

Собираем и устанавливаем:

Вот ответы, которые я дал инстал-лятору:

Ура. Postfix встал. Теперь наша за-дача его отконфигурировать.

Весто mcedit может быть vi, emacsили любой другой предпочитаемыйвами текстовый редактор — это не-критично.

Редактируем главный файл кон-фигурации postfix, обращая вниманиена следующие строчки:

�� �#� "����� $%"����� ��&#� �#" ����#�� ��� $� ��������" �

����!�����!��" ������� �� �#� �#����#�"�# � ��#� �#�"�#

� ��� ���� #� �#�"�# � �� ''� #��#

��� ��� ����� "�������

�����'�#� �#����#�"�# � �# ������ �%��!(������)� �� ���� ��(� ��)� �� �"��� ��(�� %�)� �� �"��� ��(�� �)� ������ ��� ��(������ �)� ��"��� ��(�����)� ��"� � �� ��(�"���)� ��"� �� ��(�%���)� �� %���*+

�� ��!�� �� ,�!�"���" "�� ��!�"�� -../012&�+3/2(,4256� �+728(2/26(/793

�:#� �#" ����#�� ���:#� �#����#" �����6�#� �#����#�"���� � ����� ���"� �;

����!������� ����� �"�������������� ���������!��" ����

������������ �"��������������������� �"���������

" �����(�����)�<#=�����"�)� <#� �# �#�� �#�� �"��������=�#���� "�(�"������)� <#��#�� �"�=����� (�"������)� <#� �#�"����#�� �"�=���� �(�"������)� <#� �# �" =�����(�"������)�<#���# ����#�� �"�= � ���"�(����)� <#� �# �" # � ���"�= �%��"� � (����)�<#� �#�" # �%��"� � =��"��(����)� <#� �#�" #��"��=��"�(�% ��)� <�� �"�=

���"�(�����)� <�� �����=�� ����(�"������)� <#� �#����#�� = �����(�"������)� <#��#�� �"�=������(�"������)� < �=

����#��#�� �"�#�����"����" �

���!� ( � �(����(�"� � � &� �� ����( � �(����(� �����&��� ��� ����(��� � &� �� ��)#��#�� �"�#

��� ������"�����(��"����(�� ��&�#�"�����(�"�(��� �&��� ��)#��#�� �"�#

"� ��"�����(�"�(��� �&��� ��)#��#�� �"�#

�"� ��"�����(��"����(��� � &� �� ��)#��#

�� �"�#��"� � ��"�����(��� � &� �� ��)#��#�� �"�#

������(��"� � ������(����" � &� >��� ����(��� ����(��"�"� �(�� ��"�"� � &

� � � � " � ( � � � � % � � ! ?����"�( � �(����� �"����?��!(�����(����"

�" ����(���(���� ��&���

Установка и настройка MySQLиз исходных текстов

Для установки MySQL, необходимо:� иметь gcc выше, чем 2.8.1 (egcc 1.0.2), рекомендуется

2.95.2;� создать директорию для сборки, распаковать в нее

mysql-3.23.32.tar.gz/mysql-3.23.37.tar.gz (взять наhttp://download.sourceforge.net/mirrors/mysql/);

� для версии ранее 3.23.34 распаковать туда db-3.2.3h.tar.gz (это специальная версия bdb для MySQL)

� создать группу mysql;� создать пользователя mysql (в группе mysql) (зачем ему

bash?);� ./configure —prefix=/usr/local/mysql — localstatedir=/

usr/local/mysql/data — with-unix-socket-path=путь —with-mysqld-user=mysql — disable-large-files — with-libwrap — without-debug — with-charset=cp1251 —with-extra-charsets=all;

� make (70MB/91MB);� если upgrade, то остановить mysql, сохранить базы дан-

ных и my.cfg (не забыть потом удалить!);� make install (как root)(16 MB, из них 5МБ - тест): • /usr/local/mysql/lib/mysql — эту директорию указывать

для libtool, либо занести в /etc/ld.so.conf.� при первой установке: scripts/mysql_install_db (как

root — создание таблиц с правами доступа, дает все

права пользователю root без пароля и позволяет де-лать все с базами test и test_*, кроме раздачи при-вилегий);

� chown -R root:mysql /usr/local/mysql (как root);� chown -R mysql /usr/local/mysql/data (и отдельную ди-

ректорию для mysql.sockets с правами чтения длявсех; mysql не нужны права на запись для my.cnf);

� support-files/mysql.server в /etc/rc.d/init.d для автома-тического запуска и дать ему права на исполнениеи сделать линк K00mysql из rc0.d и rc6.d на него,S99mysql из rc2.d, rc3.d и rc5.d на него;

� скопировать my-medium.cnf в /usr/local/mysql/data/my.cnf и слегка отредактировать [mysqld]:

• socket=имя-файла под Unix-socket (и в раздел [client]тоже);

• skip-locking (не блокировать доступ к данным от ДРУ-ГИХ процессов);

• log-bin #журнал изменений для репликации; • log-slow-queries; • log-update #журнал изменений; • skip-networking #если не нужен доступ по TCP/IP (а еще

лучше использовать ssh + port forward); • safe-show-database; • skip-show-database.� тестовый запуск: /usr/local/mysql/bin/safe_mysqld —

user=mysql (как root)(или сразу /etc/rc.d/rc3.d/S99mysqlstart);

Page 18: 001 Системный Администратор 10 2002

16

администрирование

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

Обратите внимание на отсутствиелишних пробелов и других невидимыхзнаков в концах строчек — это важно!

Как, наверное, стало понятно извышеприведенных файлов, я указалpostfix искать MySQL на localhost, под-ключаться пользователем postfix с па-ролем postfix, использовать базу дан-ных mail. Конечно, эти данные всеголишь для примера — вы должны илиих изменить или понять чем грозит ис-пользование паролей, сходными с ло-гинами. Понятно, что эти файлы не-зачем читать всем (намек на правиль-ный chmod).

Проверяем, все ли в порядке.

Команда должна отработать безкаких-либо сообщений об ошибках.Если все-таки она что-то вывела, при-

дется разбираться, что не понрави-лось системе.

Теперь необходимо создатьпользователя и все необходимые таб-лицы с помощью вызова mysql — p:

�� ��'������������� ����"�@5�����AB?�����%�������CD�E�� �F�� ��'���� ��" ���?� ����?�������?

�������� ���"��G������ �"�H������ �"�� �""������-�� �"�;@5�����AB?�D���% �������CD���� �F�� ��'�� ����"�@+����� �� �� ���

�� ��'���������������� �����C����" ������C���F�I0:,/04�B84?���� ����

���CJFF@

Здесь будет храниться информация одоменах, обслуживаемых postfix.

�� ��'���������������"� � �C"��" �CEF?�"��" �CEF?���"� �������C���F�I0:,/04B84?� ��"��"�� ������C���F?� �� %���������C��JF?� " �������C��JFF@

Здесь информация о почтовых пользо-вателях системы.

�� ��'� ������ ������ ������(��"� � C��"� � ������C���F� I0:,/04� B84?���������C���FF@

А здесь информация о почтовых пере-адресациях и прочем. Небольшие спискирассылки тоже можно включать сюда.

�����'���� ������ ���&��� �"��� %����&��� �"��� ����&���"�������&���� ���� ����("����&���� ����%����("����&�����" �� � �&������� �*+�����'�"� �� ���&��� �"��� %����&��� �"��� ����&���"�������&���"� � ����("����&�"�%����("����&���"� �� � �&������� �*+�����'��"� �� ���&��� �"��� %����&��� �"��� ����&���"�������&���"� � ����("����&��"�%����("����&���"� �� � �&������� �*+������'���"� � �� ���&��� �"��� %����&��� �"��� ����&���"�������&���"� � ����("����&���"��"�%����("����&���"� �� � �&������� �*+

�����'�������(��"� � �� ���&��� �"��� %����&��� �"��� ����&���"�������&�������(��"� � ����("����&����%����("����&���"� �� � �&������� �*+

���� �"����!�

� /usr/local/mysql/bin/mysqladmin — u root — p password“пароль” (при запросе пароля нажать Enter);

� /usr/local/mysql/bin/mysqladmin — u root — hlocalhost.localdomain -p password “пароль” (надо ли?);

� установка интерфейса с Perl: • взять на www.mysql.com модули Data-Dumper, DBI и

Msql-Mysql-modules; • каждый распаковать в отдельную директорию (Msql-

Mysql-modules последним); • зайти в нее; • perl Makefile.PL (опционально хочет RPC::PlServer,

RPC::PlClient, Storable, Net::Daemon); • make; • make test (mysqld должен работать); • make install (как root).� тестирование: • зайти в sql-bench; • ./run-all-tests — user=test (нужны права для записи в

директорию output, час времени и 200 МБ на диске)(connect/disconnect временами грохает mysqld!);

• можно удалить sql-bench и mysql-test.� настроить права доступа (как минимум, убрать ано-

нимный доступ).

Опции ./configure� — prefix=куда-устанавливать (множество мелочных оп-

ций по установке);� — enable-maintainer-mode [no];� — enable-shared (делать разделяемые библиотеки)[yes];

� — enable-static (10% быстрее)[yes];� — with-mit-threads (для linux 2.2 не надо);� — with-pthread (для linx 2.2 не надо);� — with-named-thread-libs=где;� — with-named-curses-libs=где;� — with-named-z-libs=где;� — enable-thread-safe-client (если клиентская програм-

ма использует потоки);� — enable-assembler;� — with-raid;� — with-unix-socket-path=куда-класть-unix-socket;� — with-tcp-port=порт [3306];� — with-mysqld-user=имя-пользователя-для-mysqld;� — disable-large-files;� — with-libwrap;� — without-debug (15% быстрее);� — without-server;� — without-docs;� — without-bench;� — without-readline (использовать системный readline

вместо встроенного);� — with-charset=кодировка-по-умолчанию (cp1251,

koi8_ru, latin1, ...);� — with-extra-charsets=список-дополнительных-кодиро-

вок (включая - none, complex, all);� — with-berkeley-db;� — with-innodb;� — with-gemini (Gemini DB).Остальное смотрите на сайте www.mysql.com

Page 19: 001 Системный Администратор 10 2002

17№1, октябрь 2002

администрирование

���� �"�� ������ �"�#�� �"�� �"��)� ����" �����

I� �"����"�� � ���

�� ��'� " ���� " ��� ��� ����� ����� CK�� ����L?M�"�����)MF@

�� ��'� " ���� " ��� ��"� � ����� C�DDD?��?M����"!H�� ����M?M#���# � � � � # � � � " � # � � � � � � ( � � � � " ! #M?M�� ��� %���M?M" �MF@

���� �������� �"����

���!�"��#���# ����#���"�����% � ��������"��#���# ����#���"����������D�#���# ����#���"�

>���� ��������� ����9��" �� ����D�D�����.� �������������� ��8 ������������" �K*=L���D���"���� �����82,9I�I� �"���"�����)�����"!H�� ������D�A!������)�����"!H�� ������D�A!����N�O�8 �������%"����.0'�6P'��.0'�6P'��������D�A!)��������� ����QP88/8E

R� � �J� �E)�O)��� ����"!� �� �"�# ����<��JEN=)� � ��� �������"!�"������" �<����D�D��=

R� � �J� �E)�O)�N� ����"!� �� �"�# ����<��JEN=)� ���QP88/8E)�"� �&����"!�"������" �<����D�D��=

R� � �J� �E)�O)N�� ����"!� �� �"�#��� ��<��S�S=)� ���QP88/8E)�� ����"�&��DD�DE�J���O�N����QP88/8EH��"���� ����'

R� � �J� �E)�O)N�� ����"!� �� �"�#����<���E�=)� ���QP88/8E)���&�����"!H�� ����'? "��&NOD?� ���&�C��������"��F

R� � �J� �E)�O)N�� ����"!� �� �"�#�"�����<��S��=)� ���QP88/8E)��&�����"!H�� ����'?�����&�"�����?�����&S?� ���� & � �� C��"��"�F

��� ���0�#���# ����#���"�#���# ����#���"�)TUVWV�O��%�$$$�������DDD�������"����������ODSE

XYZ��J��E)�E��� ����(����"!

#���# ����#���"�#�� ����(����"!)TUVWV�����%�$$$�������DDD�������"����������ODSE

XYZ��J��E)�E�����%�$$$�������DDD�������"����������ODSE

XYZ��J��E)�E� �%��%�$$$�������DDD�������"����������ODSE

XYZ��J��E)�E����#���# ����#���"�#�� ����(����"!#��)TUVWV�D

#���# ����#���"�#�� ����(����"!# �%)TUVWV�O��%$$$�������DDD�������"�����������NJS

XYZ� �J�E)�E�D���E�������SN�(D�����"!�"������" �

#���# ����#���"�#�� ����(����"!#���)TUVWV�D

�������������"���"���������������������� ������"������% ����"������"������"���"����

������������"���"����������� �������"���� �� #[\]^_� `_ab_\Vcdc_eTf#���"���

"������������#� "��������!�

�� �����"�#����" �/7938g9:./9:Ag(,A+7682&-��������� ;/793+/8,Ag,A+7686:29&-����� ���

�������������� �������� ������������;2/26(/7938g9:./9:Ag(,A+7682&-.0/,�

23/��.0/,�,+��I6/:g�6A1:g;

����"�����!��" ��������!��" ����(� "����

�� �� #� �#�"�#���"���"���#��#������������� ���" ����������� �

������������" �&-����� ���������������� ����� ������ ��� �������;

�������������" �&-������ ��;

�����'������� ���,4256(280h80������������������������ �,4256(7280g/,8��������������� �"�,4256(I/22iA0+��������������� �"�,4256(IA09�����������������NNDE,4256(+/9/Q/28���������������"�,4256(7280(9/Q68�������������"� � ,4256(.68/0(IiP:86+���������� %���+8P/769(+A,/:g��������������� ����,4256(7:+(P:86+������������"�,4256(1:+(P:86+�������������"�,4256(6A1:g(P:86+������������"� ,4256(3A,8(P:86+�������������"��"�,4256(g/,8(P:86+�����������" �,4256(,/:6+:0(P:86+����������"��"�*+

#� �#�"�#���"���"���#�"����#���N���� ����

Проверьте, имеет ли пользовательpostfix доступ к MySQL.

Запускаем postfix.

И в консоли MySQL добавляем до-мен test.ru.

И пользователя [email protected]. Об-ратите внимание на путь к почтовомукаталогу пользователя и на заверша-ющий «/» в конце строки.

Число 1000 я взял из головы —главное, что бы оно было больше пос-леднего UID в системе. В RedHatпользовательские UID начинаются с500, поэтому я думаю, что 500 локаль-ных пользователей вполне достаточ-но. А 12 — это GID группы mail на моейсистеме.

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

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

И проверяем, как у нас работаетприем почты:

В /var/log/messages должны по-явиться аналогичные строчки:

Если мы посмотрим в почтовыйспул, то увидим, что письмо принятои дожидается своей очереди.

Теперь подошла очередь установ-ки IMAP и POP3 демонов. Иначепользователям не через что будет по-лучать почту. (Из одного письма: «Ачего у меня sendmail не отдает по pop3почту Outlook’у ?»).

Распаковываем и собираемCourier-IMAP.

Тут останавливаемся и проверяем,что у нас есть из демонов, которые бу-дут проверять почту:

Обращаем внимание на наличиеauthmysql. Иначе разбираемся, поче-му не так.

Выходим из-под пользователяcourier и устанавливаем демонов:

А теперь отдадим дань конфигури-рованию:

Редактируем authdaemonrc — на-ходим строчку:

и оставляем от нее только такой вотогрызок:

Другие строки НЕ ТРОГАЕМ.Теперь указываем, где искать

MySQL и информацию о пользовате-лях:

Опция DEFAULT_DOMAIN указы-вает, что добавлять к логину, еслипользователь пытается ввести логинбез доменной части. Остальное, я ду-маю, понятно из названия и описаний.

И запускаем pop3.

Page 20: 001 Системный Администратор 10 2002

18

администрирование

����� ��������� ����D9��" �� ����D�D�����.� �������������� ��8 ������������" �K*=L��AB�3������������ ��� ����"!H�� �����AB�I� %��������"������ � �� ��� %����AB��������" ��" ��AB�IAIN��"� � ����������!�����?�����

�"������29+�N���ODD���"��AB�Q�������.� ��"� ��� ���������"� ��� ��

R� ��J���)��)�������"!����N�)�6A1:g?� � � & � � � � " ! H � � � � � � ?"�&<)))����D�D��=

R� ��J���)��)�O�����"!����N�)�6A1A79?� ��&����"!H�� ����?"�&<)))����D�D��=?���&D?�����&D

��%���O��J����" ��������%����� �"��O��J�O��" ������

����#���#��%�����#��%��B��� "��)� #���#��%��#��%���!��0��" ����"� � " �)D�DDDDNSO�8������"� � B��� C:+� / �"�h"�� � 6���

6��?� 2��I���� ����F9�" � " � � � 8h/67/9:Ag� ��� "� � %"��

�"�"���� � �"� ��"��j9�� ���� ����� ���" ����"� � !��?� ���

���"� ��� �������6���" ��#���#��%��#�� � #��%��� �����

��A!?��"�� ������ )��SOD�

������ �����%�����!�"��#���# ����#��%������% ���%�����%���#���# ����#��%�����������D�#���# ����#��%��

"������ "���� ��� ����"������ &0� ��&��%��� ����&#���#��%��#��%��

��� �"���>[ � ���f�$�>[��"�"� �f

���� " ��� � �� � �� �D� ����� ��� �� �("����&"����)� �����

#��#" "���#��%���� ����2����" ��+���i�������� ���B���"��)�#

���#��%��#��%����!��0��" ����"� � " �)D�DDDDNSON8������"� � B��� C:+� / �"�h"�� � 6���

6��?� 2��I���� ����F9�" � " � � � 8h/67/9:Ag� ��� "� � %"��

�"�"���� � �"� ��"��j9�� ���� ����� ���" ����"� � !��?� ���

���"� ��� �������6���" �� #���#��%��#�� � #��%��� ��������A!?��"�� ������ )�SOD�

+���� �" �" ������?�9.I� �!���������� ������NDDD

R� ��S��N)O�)DJ�����"!���%����� �"�)����� � "�����"� � ���#��#��%��#��%��(�� �"���

R� ��S��N)O�)DJ�����"!���%����� �"�)/�"� )� " ����&5?� � �""�� &5? !"�&I?��"�����&I?� � " �(�����&9?���� " �(�����&0?� �����(���&.? ���("����&I

R� ��S��N)O�)DJ�����"!���%����� �"�)� % � " � ) � � � � ( � C # � � # � � % � � #��%��(�� �"��� F)� �� �����������

R� ��S��N)O�)DJ�����"!���%����� �"�)�%�"�)� ������)� ��� �"������ ��%���� � "� ����EDDDD��"��" �� � �C����� � " " "��F

R� ��S��N)O�)DJ�����"!���%����� �"�)��%����"��)�<���D=� ����������

2!"�A�k���&���

l�mVn]�b`Vb]a\_Uo�Up�Vqop\Ud?�\VUV`dp��%���Zp�bp`pc_`Tc_pU�

,�"�����A�k���&���

r^TZ� Ts� ^VtpZVc?� \VUV`du� Vqae]vTc_�pUaw� ]� tpZw?� b`TZ_^epvTU� ^Ts_uZp`_t� Tb`Vnpt]�m]^VvpaUcpZZVt]�eY^]��rZT�VnpZoVqVv_YU�\T^_Uoaw�^`]W�c�^`]W_�_`mTc_tTa�\_`UTZ\_tT?�\VUV`dp�av_Ud�VnpZo�aTeo�ZV�� +�i��� VqdnZV� anTU_pU� U_\Tp� bTaot_s_�txueqVtqd�

/��" ,�"��&�����H�� ����yUV�U]U�]�Z_a�_^tTZTaU`_UV`�

P"����,�"�� &� +�i���+/8,AgH"��������

X� VU� \VWV� q]^pU� b`TmV^TUo� bVnU_� a`]W_ZoY�T�b`VnTtT�aVVqzpZTwtT�

{_epp�cps^p)

2� ���g��"��&� �|p�Z_^V�Tscpz_Uo�bVade_Upew�bTapt���c

SD}�ae]n_pc�xUV�qpsbVepsZV�T�eT~o�s_qT�c_pU�bVnUVcdp�\_Z_ed���aeT�VUb`_cTUpeoTscpaUpZ� _^`pa_U]?� UV� VZ� a_t� Z_bT~pUpt]�WZpcZVp�bTaotV�

��#���#��%����% ��0���%�����%���G

Должен запуститься и не ругатьсяни на что. Проверяем:

Как видите, система нас пустила.Наше отправленное письмо лежит идожидается нас.

В maillog должны быть записи по-хожие на эти:

Радуемся — базовая функциональ-ность достигнута. Можно смело запус-кать imap сервер аналогично pop, раз-давать пользователей и совершатьдругие необходимые телодвижения.

Но лично мне этого мало. Я не хочувидеть вирусы в своем почтовом ящи-ке и в ящиках своих работников и кли-ентов. Ставим Dr.Web.

Забираем с drweb.ru файлы:

И распаковываем их. Хотя моглибы взять rpm файлы — их содержа-ние абсолютно идентично.

Проверяем, то ли мы распаковалии туда ли.

Как видите, Dr.WEB работает в ог-раниченном режиме. То есть он мо-

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

Тщательно прочитываем /opt/drweb/doc/postfix/readme.rus.

И добавляем Dr.WEB в качествефильтра к postfix:

Редактируем /etc/postfix/master.cf,как указано в документации к Dr.Web:

и добавляем в конец следующее:

Затем тщательно читаем и редак-тируем /etc/drweb/drweb_postfix.conf.

Лично я изменил следующие пара-метры:

Перемещаем /etc/rc.d/drwebd в /etc/init.d/drwebd и с помощью ntsysv илиchkconfig, включаем автостарт Dr.WEBпри запуске системы. Тем, кто ставилDr.WEB через rpm, этого делать не

надо. Проверьте, все ли на месте.Запрещаем всяким лазить куда не

следует:

И запускаем демона Dr.WEB:

Работоспособность проверяемпростым запуском /opt/drweb/drweb-postfix. Он должен запуститься безкакого-либо писка и висеть, томитель-но выжидая и занимая консоль. А влогах должно появиться следующее:

У вас так? Значит все работает.Перезапускайте postfix и Dr.WEB вста-нет на стражу вашей почты. Можетепроверить, послав какой-нибудь ви-рус. Вы получите лишь уведомлениео том, что вы посылали вирус.

Но просто защиты мне мало. Мненеобходима еще и свежая защита. Адля свежей защиты необходимо об-новлять базы данных о вирусах. Дляэтого у Dr.Web есть обновлялка, на-писанная на perl. Для нее нужен мо-дуль String::CRC32. Делающие всеправильно могут вспомнить что напи-сано в man CPAN и с помощью installустановить этот модуль. Мне оказа-лось проще и быстрее сделать всевручную:

Файл я взял с http://www.cpan.org/modules/by-module/Str ing/Str ing-

Page 21: 001 Системный Администратор 10 2002

19№1, октябрь 2002

администрирование

����#���#��%��#���������#���������

�� ��'� ������ ������ ���" � C���" ������C�DF� gA9� g766?� �� %���������C�DF?�"��� � " �CEFF@

� � ��� %�� �� ��� ��� �� � ������ � ����� � �� ���

>���� ��������� ����9��" �� ����D�D�����.� �������������� ��8 ������������" �K*=L���D���"���� �����82,9I�I� �"����������"!��D���"���� ������D�I:I86:g:g1��D�2:�8� �D�ODDDD��D�890g��D�/793�6A1:g�I6/:g��D�/793&6A1:g� I6/:g��D��h80I��D� JQ:9,:,8y

��D�/793�6A1:g�I6/:g�+:1829�,+��.0/,�,+�

��D�/793&6A1:g�I6/:g�+:1829�,+��.0/,�,+�

����������2��" ��.0.N����������������2��" ��.0.N������������,�!�"���I6����!�����!���� �����!��" ����

B��� "��)� #���#��%��#��%���!��0��" ����"� � " �)D�DDDDNSO�8������"� � B��� C:+� / �"�h"�� � 6���

6��?� 2��I���� ����F9�" � " � � � 8h/67/9:Ag� ��� "� � %"��

�"�"���� � �"� ��"��j9�� ���� ����� ���" ����"� � !��?� ���

���"� ��� �������6���" ��#���#��%��#�� � #��%���������

��A!?��"�� ������ )���N6���" ��#���#��%��#�� � #��%O�JD�����

�� A!?� �"�� � ����� )� NN6���" �� #���#��%��#�� � #��%O�JDE����� �� A!?� �"�� ����� )���

6���" ��#���#��%��#�� � #��%O�JD�������A!?��"�� ������ )��NN

6���" ��#���#��%��#�� � #��%O�JDO������A!?��"�� ������ )���N

6���" ��#���#��%��#�� � #��%O�JDN������A!?��"�� ������ )��N

6���" ��#���#��%��#�� � #��%O�JD�������A!?��"�� ������ )��ON

6���" ��#���#��%��#�� � #��%O�JD�������A!?��"�� ������ )��E

6���" ��#���#��%��#�� � #��%��� �������A!?��"�� ������ )��SOD�

CRC32-1.2.tar.gz, и установил:

Проверяем:

update.pl должен сходить в инет насайт Dr.WEB, забрать все обновленияи перезапустить drwebd, если он есть.В логах после запуска вы должныувидеть следующее:

Видите, появились свежие обнов-ления для drweb с новыми вирусами.Теперь со спокойной душой запихи-ваем вызов update.pl в crontab. У меняон вызывается каждую ночь. ОдноНО: Необходимо периодически вруч-ную отслеживать выход новых версийdrweb. Потому что как только выйдетновый DrWeb, ваш автоматически пе-рестанет получать новые вирусныедополнения.

И последний шаг — установкаwww-почты:

Я взял последнюю версиюSquirellMail с http://www.squirrelmail.org/и установил согласно прилагающимсяинструкциям. Для ее работы необхо-дим настроенный Apache c PHP. Какэто делать я уже писал несколько раз.Да и в сети куча документов, посвя-щенным этому вопросу. Установкапростая, поэтому я тут останавливать-

ся не буду. Не забудьте — дляSquirellMail необходим запущенныйimap демон — так что не оплошайте.

Для завершения нашей эпопеи ос-талось всего два шага:

� Проверьте, все ли заработает призапуске системы. Если есть воз-можность — перезагрузитесь ипроверьте, запустился ли Dr.WEB,postfix, courier pop3 и/или imap cmysql. Отрабатывает ли update’рновые обновления и так далее.Просмотрите все конфигурацион-ные файлы еще раз — не остави-ли ли вы где-нибудь ляпов или «со-плей»? Для самостоятельной ра-боты можете посмотреть на анти-спамерные возможности drweb.

� Проверьте, прикрыт ли MySQL иDr.WEB от посторонних людей.

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

Но для меня это еще не все. Развсе равно для пользователей стоитApache с PHP, то я написал простень-кую WWW — утилитку для управле-ния почтовыми пользователями. Дляее работы необходимо создать вMySQL такую таблицу:

И руками занести туда значениявроде “admin”, ’password’,0.

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

По адресу www.samag.ru/2002/01/multik/ лежат 3 файла auth.php,global.php, index.php. Просто положи-те эти три файла в один каталог, дос-тупный вам. Поправьте значения вglobal.php. Все, можете вызывать ипользоваться. Логин и пароль — те,которые вы вручную добавили в таб-лицу admins.

Ну а дальше, я думаю, вы пойме-те. Утилитка писалась «на коленке»,поэтому я вполне понимаю, что мож-но написать лучше и красивее. Пи-шите. Удачи !

А тем, кто до сюда дочитал — ма-ленький бонус.

Если вы поглядите на это:

К вашему большому сожалениювы не увидите строчек:

Либо вы увидите эти строчки, нопочему-то нормальные почтовые кли-енты (к примеру, TheBat или stuphead)не смогут авторизоваться для отправ-ки почты. Только для отправки! В чемже дело ?

Дело в одной маленькой библио-теке, называемой Cyrus-SASL. К со-жалению, ее писали люди, которыеписали ее неправильно. Метод sasldbв ней важнее всех.

Внимание, если /etc/sasldb не пус-той (смотреть вывод sasldblistusers),то в выводе postfix появляются строч-ки про DIGEST-MD5 и CRAM-MD5.Если пустой -то не появляются. Еслив sasldb есть хоть одна запись, тоаутентификация с участием методовLOGIN, DIGEST-MD5 и CRAM-MD5идет через sasldb, НЕВЗИРАЯ на то,что написано после pwcheck_method.Поэтому, если у вас есть активно миг-рирующие пользователи с нормаль-ными почтовыми клиентами (Outlookи Mozilla — не подходят — они оба ис-пользуют только метод PLAIN), то дляотправки почты с таких клиентов ихнадо заводить вручную, используя ко-манду аналогичную этой:

Вот такой вот SASL. Правда, обе-щают, что в v2 будет все по честному,но пока v2 не выбралась из бета-со-стояния, да и postfix в стабильных вер-сиях не поддерживает Cyrus-SASL v2.

Courier-IMAP использует SASL подругому, поэтому с ним все в поряд-ке. Вот теперь точно все. Удачи!

Page 22: 001 Системный Администратор 10 2002

20

администрирование

Данная статья предназначена в пер-вую очередь для тех, кто, считая, что«качественный продукт не может бытьбесплатным», доверил управлениесвоими серверами дорогой операци-онной системе и вынужден периоди-чески смотреть на «синий экран смер-ти», терять время на перезагрузки ииногда на восстановление самой ОС.

Приведем сравнение операцион-ных систем Microsoft Windows NT и

Linux по нескольким критериям, непретендуя на детальное сравнение,которому посвящено уже много ста-тей.

Windows NT:

� Является коммерческим ПО, за ис-пользование каждой его копии не-обходимо платить.

� Производитель обещает бесплат-

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

� В комплект поставки входит опе-рационная система, утилиты ад-министрирования, набор простыхигр, www- и ftp-сервер IIS.

С WINDOWS НА LINUX

МИГРАЦИЯ

Сначала давайте выяснимдля себя,зачем нам это нужно?Если ваш сервер работаетпод управлением Windowsи никаких нареканийк стабильности и скоростиего работы нет, не стоитничего менять.Как известно, лучшее - врагхорошего.К сожалению, везет далеконе всем.ДМИТРИЙ ГАЛЫШЕВ

Page 23: 001 Системный Администратор 10 2002

21№1, октябрь 2002

администрирование

� Нужные Вам утилиты, не входя-щие в состав OС, приобретаютсяотдельно.

� Документация к системе приобре-тается отдельно.

� Выполнение отдельных задач кли-ентом на сервере невозможно.

Linux:

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

� Ядро ОС и поставляемые с нимпрограммы Вы используете на свойстрах и риск без каких-либо гаран-тий. Это не значит, что техническаяподдержка отсутствует — вы може-те обратиться за ней к автору про-граммы.

� В дистрибутив входит комплект ин-тернет-утилит как серверной, таки клиентской направленности, ин-струменты для разработки сетево-го взаимодействия с другими ОС,игры и многое другое.

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

� В состав каждого дистрибутивавходит комплект документации поОС и всем установленным про-граммам.

� Пользователи могут не только вы-полнять задачи на сервере, но ипланировать их выполнение в своеотсутствие.

Если Вы хотите узнать больше,обратитесь к статье «MicrosoftWindows NT Server 4.0 против UNIX»Джона Кирха, сетевого консультантаи сертифицированного специалистаMicrosoft (Windows NT) на http://www.linux.org.ru/books/unix-nt.html.Статья датирована 1998 годом, и стех пор многое изменилось, но рас-становка сил осталась прежней.

Управление Linux основано не на«интуитивно понятном интерфейсе»,а на правке различных конфигураци-онных файлов после чтения докумен-тации, которая написана в основномна английском языке, хотя переводовс каждым годом становится большеи больше. Если Вы нелюбознательны

или нетерпеливы, эта ОС не для Вас.Не испугались? По прежнему полнырешимости? Ну что же, начнем осва-ивать новую ось. В любом случае до-говоримся, что все работающие сер-вера остаются работать до тех пор,пока к ним обращается хотя бы одинпользователь.

Для начала рассмотрим задачу ос-вобождения сервера под управлени-ем Windows NT от обязанностей ос-новного контроллера домена (PDC).Основное преимущество доменнойструктуры — выполнение скриптов,определенных администратором длявыполнения при входе и выходепользователя домена. Также, с помо-щью Samba, мы возьмем на себя за-дачи файл-сервера — предоставле-ние коллективного доступа к своимфайлам и папкам.

Применить здесь понятие «к ре-сурсам» было бы не совсем коррект-но, так как к ресурсам относятся вре-мя процессора, память и так далее.Удаленные пользователи могут ис-пользовать и их, но Windows NT та-кой возможности не предусматрива-ет.

Системы Microsoft Windows 3.11, 9хи NT используют для предоставлениясовместного доступа к файлам, пап-кам и принтерам протокол ServerMessage Block (SMB). В Linux за рабо-ту с SMB отвечает пакет Samba. О немего создатели пишут следующее:«Вот короткий список того, что дела-ет Samba. Для многих сетей можносказать коротко: «Samba предостав-ляет полноценную замену серверамWindows NT, Warp, NFS или Netware».

� SMB сервер для предоставлениядоступа к файлам и принтерам,клиентам с рабочих станцийWindows 95, Warp Server и подоб-ным.

� Сервер имен NetBIOS, который ковсему прочему поддерживает спи-сок доступных компьютеров всети. Samba может выступать вроли главного обозревателя Ва-шей сети.

� SMB клиент позволяет пользовать-ся ресурсами других компьютеровсети (как файлами, так и принте-рами) из Unix, Netware и другихОС.

� Расширение клиента «tar» позво-

ляет делать резервные копии уда-ленных ресурсов.

� Утилиты командной строки, под-держивающие некоторые возмож-ности администрирования NT, ко-торые могут быть использованы вSamba, NT workstation и NT server.

Вы можете получить больше инфор-мации на нашем сайте: http://samba.org/samba».

Если Samba еще не установлена,обращаемся к компакт-диску с дист-рибутивом и устанавливаем все па-кеты, содержащие в имени слово«samba». Типичные настройки обыч-но описаны в файле /etc/samba/smb.conf-sample и подходят большин-ству пользователей.

Рассмотрим его поподробнее.Файл состоит из секций, которые оп-ределяются именем в квадратныхскобках.

В секции [global] объявляются об-щие переменные, влияющие на рабо-ту демонов.

В секции [homes] предоставляет-ся возможность монтирования уда-ленными пользователями своих лич-ных папок, находящихся на сервере.

Секция [printers] открывает дос-туп ко всем установленным в систе-ме принтерам.

Переименуем файл /etc/samba/smb.conf-sample в smb.conf и начнемего править под себя.

Полезными могут оказаться «под-становочные переменные», которыепри чтении заменяются актуальнымидля сеанса значениями. Например,«%u» будет заменено именем подклю-чающегося пользователя, а «%L» —NetBIOS-именем сервера. Полный спи-сок этих переменных Вы найдете вman-руководстве к smb.conf.

Вот некоторые глобальные пара-метры, на которые стоит обратитьвнимание:

workgroup — задает имя рабочейгрупппы или домена, в который вхо-дит компьютер.

hosts allow — список компьютерови сетей, которым разрешен доступ,разделенный пробелами.

guest account — имя пользовате-ля с правами гостя. По умолчанию —это nobody.

Пользователь должен быть заре-гистрирован в системе. Можно ука-

Page 24: 001 Системный Администратор 10 2002

22

администрирование

зать с помощью параметра usernamemap файл, содержащий толкованиепередаваемых клиентом имен длясервера. Файл будет читаться пост-рочно; в строке слева от знака «=»должно стоять имя, воспринимаемоесервером, справа — соответствую-щее ему имя, которое может переда-вать клиент.

Например, если в файле содер-жится строка nobody = guest pcguestпользователям guest и pcguest будетпредоставлен доступ как пользовате-лю nobody.

security — один из важных пара-метров конфигурации — модельаутентификации.

Возможны варианты:security = user — для получения

списка ресурсов пользователь дол-жен быть опознан сервером. Будьтевнимательны: по умолчанию ресурсы,открытые гостям, не будут доступнытем, кого сервер «не знает».

security = share — получение спис-ка ресурсов не требует аутентифика-ции. Клиент посылает запрос при под-ключении к конкретному ресурсу.

security = server — с точки зре-ния клиента, эта модель ничем не от-личается от первой. Разница в том,что полученные имя/пароль Samba по-пытается проверить на доверенномсервере (например НТ). Если попыт-ка провалится, для этого соединениямодель сменится на «user».

security = domain — отличается отпредыдущей тем, что аутентификацияпроисходит на PDC или BDC. Паролидолжны передаваться в зашифрован-ном виде.

encrypt passwords — шифрова-ние паролей. По умолчанию этот па-раметр выставлен в «no» и пароли пе-редаются по сети открытым текстом.

interfaces — привязка к конкрет-ным интерфейсам. Можно указатьимя интерфейса со звездочкой вмес-то номера, тогда привязка будет ковсем найденным интерфейсам этоготипа. Также можно указать просто IP-адрес или пару IP/маска сети.

local master — определяет, пре-тендовать ли на роль локального обо-зревателя сети.

os level — так называемый «уро-вень» ОС. Для справки: у НТ-сервераэтот параметр равен 32, у PDC — 64.Максимальное значение — 255.

domain master — определяет, пре-тендовать ли на роль основного обо-зревателя домена. Если сеть состоитиз нескольких сегментов, то локаль-ные обозреватели каждого сегментабудут синхронизировать свои спискис ним.

preferred master — сообщает де-мону nmbd, что он является приори-тетным обозревателем рабочей груп-пы или домена, и это вынуждает егоустраивать выборы при запуске, а вслучае проигрыша — каждые 6 минут.

wins support — включает поддер-жку Samba-сервером WINS —Windows Internet Naming Service, служ-бы определения адресов, сопоставля-ющей имена компьютеров в сетиMicrosoft с адресами IP.

wins server — указывает IP-адресWINS-сервера сети. Этот параметр неможет указывать на свой IP, т.е. ис-пользуется только в случае, когдаwins support = no.

domain logons — позволяетSamba выступать в роли контролле-ра домена.

logon script — задает имя скрип-та, выполняемого при входе пользо-вателя в домен.

logon path — указывает на ката-лог, где будут храниться профилипользователей.

Из параметров, применимых к кон-кретным разделяемым ресурсам, сле-дует отметить:

comment — краткое описание ре-сурса, выводимое большинством кли-ентов рядом с его именем.

path — реальное расположениеразделяемого ресурса в файловой си-стеме сервера.

browseable — определяет, будетли выдаваться имя ресурса на запросо доступных ресурсах сервера.

writeable — определяет, возмож-на ли запись или модификация фай-лов ресурса пользователем.

guest ok — разрешает доступ к ре-сурсу всем пользователям сервера.(См. глобальный параметр security).

valid users — список пользовате-лей, которым разрешен доступ к ре-сурсу. Как и в любой список пользо-вателей в файле smb.conf можно до-бавлять и группы, предварив имягруппы символом «@».

write list — список пользователей,которым разрешена запись и модифи-

кация файлов ресурса. Значение па-раметра writeable для этих пользова-телей не учитывается.

create mask — стандартная UNIX-маска, определяющая права доступак вновь создаваемому файлу.Directory mask определяет права дос-тупа к вновь создаваемому каталогу.

Полный список опций, употребляе-мых в файле, находится в man-руко-водстве к smb.conf. После редактиро-вания рекомендуется проверить его напредмет ошибок и противоречий с по-мощью программы testparm. Еслиошибки есть, она сообщит о них и, ско-рее всего, подскажет причину их воз-никновения.

Сначала настраиваем Samba какобычного сетевого клиента — она недолжна претендовать ни на роль ло-кального обозревателя, ни тем бо-лее — контроллера домена. Если та-ковые уже есть, то присваиваемзначение «no» параметрам localmaster, domain master и preferredmaster.

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

Мне не известен сколько-нибудьреальный способ переноса базыпользователей из Windows NT в Linux,поэтому придется делать это вручную.Неудобно, но в этом есть свои поло-жительные стороны — найдется не-сколько неиспользуемых учетных за-писей, а также можно будет перерас-пределить пользователей по группам.

На момент написания статьиSamba (версии 2.2.5) имеет собствен-ную базу пользователей, но не под-держивает пользователей, не имею-щих учетной записи в системе. Раз-работчики обещают со временем пе-рейти на независимую базу пользова-телей, но пока придется пользовате-лей заводить сначала в системе.Пользователям, у которых не будетдоступа к терминалу сервера (в иде-але всем, кроме администратора) на-значаем /bin/false в качестве команд-ного интерпретатора и блокируемучетную запись, после чего пропи-

Page 25: 001 Системный Администратор 10 2002

23№1, октябрь 2002

администрирование

сываем их в базе Samba командойsmbpasswd дважды: с ключом «-a» —для занесения в базу, с ключом «-e» —для снятия блокировки с записи.

Хорошо, если новая операционнаясистема ставится на специально куп-ленный сервер, еще лучше, если сер-вер куплен с предустановленной нуж-ной нам ОС. Но как быть, если сер-вер один и нельзя его трогать до техпор, пока все пользователи не смогутполучить гарантированный доступ ксвоим файлам? Придется использо-вать любой доступный компьютер как«временный сервер». На него ставимтот же дистрибутив, что предполага-ем ставить на основной сервер, и по-степенно перенесем все ресурсы, пре-доставляемые старым сервером.

Какая машина справится с этойработой зависит от предполагаемойнагрузки. Достоверно известно, чтоCeleron 700/196Mb RAM/30Gb HDD всостоянии обслуживать 15 клиентов,интенсивно работающих с большимколичеством файлов при средней на-грузке ~10%.

Разделяемые SMB ресурсы делим на:

� Общедоступные (папка с драйве-рами и дистрибутивами программ,«помойка»).

� Доступные группе (папки с данны-ми, с которыми работает ограни-ченное количество лиц, напримерпапка с базами бухгалтерской про-граммы).

� Домашние (папки привилегиро-ванных пользователей, доступныетолько им).

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

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

������������������ ���������� ���������

������������������������������������������������ � � � ����� �� ��� �����������������

����������� ����������������� �����������������

Если в Вашей сети используютсядомены, проверьте smb.conf сервера:

� Шифрование паролей должнобыть включено.

� Сервер должен поддерживатьвход пользователей в домен и пре-доставлять разделяемый ресурсNETLOGON.

� Сервер должен быть главным обо-зревателем домена.

Если все в порядке, можно добав-лять рабочие станции в домен.

Рабочие станции, функционирую-щие под управлением Windows NT/2000, используют так называемые«машинные» учетные записи — методпроверки подлинности рабочей стан-ции (не пользователя), чтобы избе-жать входа в домен рабочей станциис таким же именем NetBIOS и получе-ния прав пользователя домена. Рабо-чие станции, функционирующие подуправлением Windows 9x/Me, такихучетных записей не используют, по-этому не могут считаться полноправ-ными членами домена.

Существует два метода создания«машинных» учетных записей — руч-ной и автоматический.

Первый метод подразумевает вы-полнение вручную трех команд на сер-вере для каждой рабочей станции до-мена:

Вместо <имя_машины> подстав-

ляется NetBIOS-имя рабочей станциидомена.

Второй метод рекомендован раз-работчиками Samba как более безо-пасный и требует лишь добавленияв секцию [global] строки:

Это подразумевает, что в ката-логе /usr/bin существует скриптadduserscript примерно следующегосодержания:

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

После того, как вся нагрузка бу-дет перенесена на «временный» сер-вер, а старый сервер — выключен,подождем денёк-другой возникнове-ния проблем и только послеэтого на-чинаем установку Linux на основнойсервер. После установки системыконфигурационные файлы и файлыпользователей просто переносятся с«временного» сервера.

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

Старому серверу меняем NetBIOS-имя и перезапускаем Samba. Новомуприсваиваем имя старого. Перезапус-каем Samba.

Все. Можем переходить к заменелюбимого лакомства для Nimda иCodeRed — Microsof t InformationServer на самый популярный вInternet www-сервер Apache, прокси-сервер Squid и ftp-сервер proftpd.

Но это уже немного другая исто-рия...

��������������������������� �������

������� �������������������������� !"#!$% &'(� ��� �����)���� � !"#!$% �&'(*

���������������� !"#!$% &'(* ���������������������� !"#!$% &'(

�+���������� �������� ����������������������

��������)�������*�

���� �� � �� ���� �� ��� ���������� �� ���� ,�

Page 26: 001 Системный Администратор 10 2002

администрирование

ЧТО ТАКОЕSAMBA?

СЕРГЕЙ ЯРЕМЧУК

[email protected]

Page 27: 001 Системный Администратор 10 2002

25№1, октябрь 2002

администрирование

Я думаю, что утверждение о том,что самой популярной операционнойсистемой для клиентских машин яв-ляется Windows, не вызовет большихспоров. Хотя с появлением таких про-дуктов, как OpenOffice.ru, и активно-му продвижению своих продуктовкомпаниями AltLinux и ASPLinux, по-ложение несколько изменилось, но домассовости еще дело не дошло. По-этому большинство пользователейпродолжают набирать документы вWord’e и бродить по Интернету с по-мощью Internet Explorer. А вот в каче-стве сервера положение последнейуже не так однозначно, здесь уже иг-рают роль NetWare от Novell и, конеч-но же, Unix. Плюс за последний годпришлось всем потесниться из-за по-явления новых «игроков» на этомрынке - операционных систем с откры-тым кодом - Linux, FreeBSD иOpenBSD, которые уже сейчас зани-мают немалый процент рынка серве-ров. Прежде всего по причине своейнадежности, устойчивости, совмести-мости со множеством платформ и бе-зопасности. Поэтому сейчас систем-ному администратору приходится ча-сто решать вопросы интеграции сер-веров под управлением Linux/Unix всеть, где преобладают клиентскиемашины от Microsoft, особенно в ка-честве файл-серверов или серверовпечати.

Так как чуда от Microsoft особеннождать не приходится и Windows вряд-ли научится работать с сетевой фай-ловой системой Unix (NFS) стандарт-ными средствами, то по принципугоры и Магомета, просто научили Unixпритворяться, будто бы он - WindowsNT.

Взаимодействие компьютеров всети Windows построено на использо-вании протокола SMB (Server MessageBlock - блоки серверных сообщений),который обеспечивает выполнениевсех необходимых в этих случаях за-дач по открытию и закрытию, чтениюи записи, поиску файлов, созданию иудалению каталогов, постановке за-дания на печать и удалению его отту-да. Все необходимые для этого дей-ствия реализуются в Unix-подобныхоперационных системах посредствомиспользования пакета SAMBA. Что жедолжен обеспечить SAMBA сервердля нормальной работы в сети

��������������������� �����������

������ ��������������� ���������� ������������������������������

Windows машин? Во-первых, контрольдоступа, который может быть реали-зован либо на уровне ресурсов (sharelevel), когда какому-либо ресурсу всети назначается пароль и соответ-ствующие правила использования(«только для чтения», например), при-этом имя пользователя не имеет аб-солютно никакого значения. Либо бо-лее совершенная и гибкая организа-ция на уровне пользователя, когдадля каждого пользователя создаетсяучетная запись, где помимо имени ипароля содержится вся необходимаяинформация о правах доступа к ре-сурсу. И прежде чем получить доступк требуемому ресурсу каждый пользо-ватель проходит аутентификацию,после успешного прохождения кото-рой ему и предоставляется права наиспользование согласно учетным за-писям. Во-вторых, необходима эмуля-ция прав доступа, определяемых фай-ловой системой. Все дело в том, чтоу рассматриваемых систем права до-ступа к файлам и каталогам на дискеорганизованы по-разному. В Unix тра-диционно существует три категориипользователей файла - владелец(owner), группа (group) и остальные(other). Каждому из этих субъектовмогут быть предоставлены права начтение (read), запись(write) и выпол-нение ( execute). В Windows NT систе-ма доступа несколько гибче, доступпредоставляется нескольким группамили пользователям, причем соответ-ствующие права доступа определяют-ся раздельно для каждого субъекта.Поэтому полноценно эмулироватьсредствами SAMBA права доступазаложенные в NTFS, невозможно. Ас клиентами, работающими под уп-равлением Windows 9x, дело обстоитиначе. Еще со времен дедушки ДОС,по причине того, что система одно-пользовательская и ни о каких пользо-вателях, а тем более группах, не мог-ло быть и речи, для файловой систе-мы FAT определено всего четыре ат-рибута - только чтение (read only), си-стемный (system), архивный (archive)и скрытый (hidden). Плюс ко всему вWindows, в отличие от Unix, имеет осо-бое значение расширение файла, такфайлы, предназначенные для выпол-нения, имеют расширение - exe, com,bat. Соответствия между правами до-ступа Unix и DOS выражаются так:

� только для чтения - чтение, записьдля владельца;

� архивный - выполнение для вла-дельца;

� системный - выполнение для груп-пы;

� скрытый - выполнение для группы.Вот с проблемами так или иначе

разобрались. Давайте разберемсятеперь конкретно с реализацией и на-стройкой SAMBA в Linux. Для работыSamba необходимо, чтобы были запу-щены два демона: smbd обеспечива-ет работу службы печати и разделе-ния файлов для клиентов Samba, та-ких как Windows всех мастей; демонnmbd обеспечивает работу службыимен NetBIOS, а также может исполь-зоваться для запроса других демоновслужб имен. Для доступа к клиентамиспользуется протокол TCP/IP. Какправило, Samba устанавливаетсявместе с дистрибутивом Linux. Какпроверить? Просто дайте команду:

и вы должны получить что-то вродеэтого:

Если нет, то идите на f tp://f tp.samba.org/pub/samba/samba-latest.tar.gz или практически на любойсервер с программами для Linux и ка-чайте в виде rpm или исходников. Па-кет прост в установке, поэтому, что-бы не занимать места, будем считать,что он у вас установлен. Теперь да-вайте проверим, запущен ли демон:

У меня уже запущен. Если у васнет, то в Linux Mandrake, например,чтобы он запускался при старте от-метьте нужный пункт в: DrakConf -стартовые сервисы или control-panel- Servise Configuration в Red Hat, обыч-но этого бывает достаточно, или за-пускайте вручную: ./etc/rc.d/init.d/smbstart. Единственный конфигурацион-ный файл Samba называется smb.confи находится в каталоге /етс иногда(в AltLinux, например, в каталоге /etc/

������������������������������������

���� !!"�""�#$$$"%&"'( #�%#"�""����)

Page 28: 001 Системный Администратор 10 2002

26

администрирование

samba). Сервис SAMBA считывает егокаждые 60 секунд. Поэтому измене-ния внесенные в конфигурацию всту-пают в силу без перезагрузки, но нераспространяются на уже установлен-ные соединения.

Вот за что я люблю Linux - так этоза то, что конфигурационные файлыявляются обычными текстовыми( ктому же хорошо комментированныевнутри), и для того чтобы задейство-вать большинство параметров доста-точно только раскомментировать со-ответствующую строчку. Файлsmb.conf - не исключение. Он состоитиз именованных разделов, начинаю-щихся из имени раздела, заключен-ного в квадратные скобки. Внутрикаждого раздела находится ряд пара-метров в виде key=value. Файл кон-фигурации содержит четыре специ-альных раздела: [global], [homes],[printers] и отдельные ресурсы(shares). Как следует из названия,раздел [global] содержит наиболее об-щие характеристики, которые будутприменяться везде, но которые, впро-чем, затем можно переопределить всекциях для отдельных ресурсов.

Значения типичных параметровсекции global:

При хранении базы паролей надругом SMB-сервере используютсязначения security = server и passwordserver = name_server_NT. В случаеесли сервер является членом доменаиспользуется значение security =domain, пароль для доступа указыва-ется в файле определенном с помо-щью опции smb passwd file = /path/to/file.

Кроме того, при регистрации могутиспользоваться шифрованные(encrypted) и незашифрованные (plain-text) пароли. Последние используютсяв старых Windows (Windows forWorkgroups, Windows 95 (OSR2), всеверсии Windows NT 3.x, Windows NT 4

(до Service Pack 3). Для включения ва-рианта использования шифрованногопароля используется опция encryptpassword =yes (по умолчанию исполь-зуются не шифрованные пароли).

Для правильного отображения рус-ских имен файлов используются сле-дующие опции: client code page = 866и character set = koi8-r.

Опция interfaces = 192.168.0.1/24 -указывает в какой сети (интерфейсе)должна работать, программа еслисервер подключен сразу к несколькимсетям, а при установке параметра bindinterfaces only = yes, сервер будет от-вечать на запросы только из этих се-тей.

hosts allow = 192.168.1. 192.168.2.127. - определяет клиентов, для ко-торых разрешен доступ к сервису.

В секции global возможно исполь-зование различных переменных дляболее гибкой настройки работы сер-вера, после установки соединениявместо них подставляются реальныезначения. Например, в директиве logfile = /var/log/samba/%m.log , параметр%m помогает определить отдельныйлог-файл для каждой клиентской ма-шины. Наиболее употребительныепеременные, используемые в секцииglobal:

Включение параметров preservecase и short preserve case заставляютсервер сохранять всю вводимую ин-формацию с учетом регистра симво-лов (в Windows регистр не имеет зна-чения, а во всех Unix это не так).

Раздел [homes] позволяет пользо-вателям подключаться к своим рабо-чим каталогам без явного их описа-ния. При запросе клиентом своегокаталога, например //sambaserver/sergej, система ищет соответствую-щее описание в файле и, если не на-ходит его, то просматривает наличиеэтого раздела. Если раздел существу-ет, то просматривается файл паролейдля поиска рабочего каталога пользо-

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

Типичное описание раздела:

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

Параметр path указывает на ката-лог, в котором располагается ресурс,параметр public указывает, может липользоваться ресурсом гость, аprintable - может ли использоватьсяданный ресурс для печати. Параметрwrite list позволяет задать пользова-телей, которым разрешена запись вресурс независимо от значенияwritable (в данном примере это пользо-ватель administrator и группа sales).Возможно использование и противо-положного списка - read list. Если естьнеобходимость скрыть некоторыефайлы, то в Unix/Linux для этого имяфайла должно начинаться с точки (па-раметр hide dot files, который регули-рует отображение скрытых файлов,по умолчанию = yes). Но кроме этогоесть возможность задать шаблоныимен скрытых файлов, для этого ис-пользуется параметр hide files. Каж-дый шаблон начинается и заканчи-вается с символа косой черты «/» иможет содержать символы, применя-емые в регулярных выражениях. На-пример: hide files = /*.log/??.tmp/. Новсе эти ухищрения обходятся пользо-вателям очень просто - установкой ре-жима «показывать скрытые и систем-ные файлы» проводника Windows.Для уверенного ограничения доступ-

��*�����+,-./0123345678976,:17;<=:>0123349?:@,A��� �

�����������+,-.?:19:179?:@,���B��������+C<--:6@71,>DC<@<14>

9,E:69<C6:?9<>?@931<?-<@17?:@,������*+F��51781:G:6,:0<?@:9<0<

9H<E7I������*+���0<?@:9<>9H<E8731:J:6K

������������+����F5,-.3<EC<@<�14-1781:G:60<?@:9<>9H<E9?,?@:-2

�������F+����5L1<9:6ME<?@237������6721<96:3<NM8<97@:N.D�������F+������72@:6@,O,C7P,.67

<?6<9:,-:6,,371<N.�

Q��71H,@:C@217RS67CN,:6@?C<>-7�G,6:I9<8-<T64:867=:6,.A��UVDA��WXDYWZW[AW,@�E�K

Q��W��\][(�,-.C<-3M^@:17CN,:6@7�Q_�W��\][(�,-.?:19:17(`a\`�QB�9:1?,.(`a\`�Q]�]b�7E1:?C<-3M^@:17CN,:6@7�QX�E7@7,91:-.�Q��,-.3<NM8<97@:N.D17;<@7^J:0<?

?:19,?7-,�Qc�E<-7G6..E,1:C@<1,.3<NM8<97@:N.

Q��

��������������+c���)����������5C<--:6@7�1,>C<@<14>9,E:69<C6:?9<>?@9?:@,��� ����d�+��5<31:E:N.:@949<E,@MN,1:?21?9?3,?C:31<?-<@17� �����d� + F�� 5 1781:G7:@ I�� �8731:J7:@K873,?M9E<-7G6^^E,1:C@<1,^���������+"�V"531797E<[email protected]<9M?<8E7664HO7>N<9�������F���+"��V5@<T:D6<@<NMC<EN.C7@7N<0<9

����d����������+b��d��(��ee����+��������������d��+F�� �����d�+���������d�+�� ����d���+������������D���d��

Page 29: 001 Системный Администратор 10 2002

27№1, октябрь 2002

администрирование

ности (возможности удаления) файла(каталога) используйте параметры:veto files и delete veto files. С CD-ROMдисками дело обстоит несколькосложнее.

Все дело в том, что в Unix-подоб-ных системах понятие диска отсут-ствует как таковое, и для того чтобыполучить доступ к нужному устрой-ству, оно первоначально должно бытьсмонтировано в дерево каталогов (#mount -t iso9660 /dev/cdrom /mnt/cdrom). А после использования, что-бы не разрушить файловую систему,должно быть размонтировано (#umount /dev/cdrom), иначе устройствопросто не отдаст диск. Если у вас насервере запущен демон autofs, то про-блема решается просто. Для того что-бы устройство которое не использу-ется в течении некоторого времени,было автоматически размонтировано,установите нужное значение парамет-ра timeout в файле /etc/auto.master,например:

А затем установите параметры длясоответствующего устройства в фай-ле /etc/auto.misc:

После всего прописываем в /etc/smb.conf следующие строки, чтобысделать доступным данный ресурс:

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

Теперь при обращении к ресурсуавтоматически монтируется CD-ROM.А в идеальных случаях и размонтиру-ется. Вся проблема в том, что реше-

ние о закрытии ресурса должен при-нять сервер и все потому, что клиен-ты, как правило, не извещают об этом.Но наиболее частой причиной явля-ется то, что ресурсом могут одновре-менно пользоваться сразу несколькопользователей или на одном компью-тере оставлен открытый файл на дан-ном ресурсе. Поэтому CD-ROM авто-матически не размонтируется, един-ственный приемлемый способ, чтобыосвободить ресурс - посмотреть с по-мощью утилиты smbstatus номер про-цесса, использующего данный ресурс,и убить его командой # kill pid_number(или kill -s HUP pid_number).

Установив необходимую конфигу-рацию необходимо теперь создатьучетные записи пользователей (заисключением гостевого входа с мини-мальными правами nobody). Для ин-тентификации пользователей SAMBAиспользуется файл /etc/samba/smbpasswd, в котором содержатсяимена и зашифрованные паролипользователей. Так как механизмшифрования в сетях Windows-машинне совместим со стандартными Unixмеханизмами, то для заполнения фай-ла паролей используется отдельнаяутилита - smbpasswd.

В этом примере добавляется но-вый пользователь sergej с фиктивнойоболочкой, принадлежащий группеsales и домашним каталогом /home/samba/sergej. Затем создается парольдля пользователя sergej.

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

Для этого в секции [global] необ-ходимо записать такие строки:

Далее каждый принтер описывает-ся как дисковый ресурс с единствен-

ным исключением, параметр printable= yes. Например:

После создания файла протести-руйте его с помощью утилитыtestparm, но при помощи данной про-граммы можно обнаружить лишь син-таксические ошибки, а не логические,поэтому нет никакой гарантии, чтоописанные в файле сервисы будуткорректно работать (при тестирова-нии будут выведены все установки -даже те, которые установлены по-умолчанию). Но если программа неругается, можете надеяться, что призапуске файл будет загружен без про-блем. А правильность установки прин-тера можно проверить с помощьюутилиты - testprns. Плюс не забывай-те о log-файлах - при возникновениипроблем там иногда можно найти ре-шение.

Теперь немного о хорошем. Кон-фигурирование Samba - довольносложная процедура, но с дистрибути-вом поставляется инструмент админи-стрирования на основе Web, которыйназывается swat (Samba WebAdministration Tool). Swat запускаетсяв виде сервиса или с помощью сер-вера Apache, и предназначен для ре-дактирования файла smb.conf, а так-же для проверки состояния, запускаи остановки демонов Samba. Для ра-боты в виде сервиса в файле /etc/services должна быть обязательнострока swat 901/tcp, а в файле /etc/inetd.conf - swat stream tcp nowait.400root /usr/local/samba/bin/swat swat. Те-перь для запуска Swat в окне браузе-ра введите:

После всех изменений в файлеsmb.conf иногда потребуется пере-запустить демон smb: /etc/rc.d/init.d/smb restart.

Если после всех перечисленныхдействий так и не удалось организо-вать доступ к ресурсам SAMBA, то вдальнейшей настройке помогут такиеутилиты, как ping, nmblookup или накрайний случай tcpdump. Вот и все.

����e��F��+���U##"D��D�����D���B � ��B�����

����������+��������� �����d�+��

���� �������������� f�������+#"

����������+��������������dF+F�������������+��������������5-<6�

@,1<97@M1:?21?7,-::@3179<@<NMC<����������������+���������������5

:?@:?@9:66<g@,@<=C,-<6@,1<976,.E<N�T64;4@M<3,?7649O7>N:�����e����,67=:6:<;H<E,-<2C787@M,<?@7NM64:E7664:�

5������������e�d�������������������������d��������

5������� ��������

������������+�������������5O7>N<3,?76,.31,6@:1<9D3<ECN^=:664HC?,?�@:-:

d����������+F��5D2C78497:@676:<;H<E,-<?@M79@<-7@,=:?C<0<9CN^=:6,.9?3,?<C?:@:94H1:?21?<9

�������� + d���� 5 ?,?@:-7 3:=7@,IEN._����-<T:@:J:,?3<NM8<97@M?.��K

��������������+�B�������d������52C78497:@67C7@7N<09C<@<14>3<-:J7^@?.87E76,.673:=7@M��� ����d�+F���������d�+F�������dF+F��

�������d���d�����U"

Page 30: 001 Системный Администратор 10 2002

28

администрирование

Стандартных решений не существует. Каждый сис-темный администратор рано или поздно начинает пи-сать свои скрипты, которые облегчают его работу, из-бавляя от рутины. Для автоматизации в Unix-системахтрадиционно применяются командные оболочки (типаbash или ksh, разновидностей оболочек достаточномного) и язык Perl. Причем, следуя философии Unix, этиоболочки используют для решения проблемы целыйнабор инструментов, выполняющих небольшие частныезадачи: ls, wc, sort, grep, diff, tar, ...

Обычно простые задачи выполняются в команднойоболочке запуcком соответствующих инструментов иорганизацией потока данных. Для более сложных за-дач требуются и более сложные инструменты, напри-мер, awk, sed или даже Perl. Так принято.

Однако хотелось бы обратить внимание системныхадминистраторов на такой сценарный (скриптовый)язык как Python. Этот язык, благодаря своим хорошимкачествам, о которых поговорим далее, уверенно заво-евывает популярность, в том числе для задач систем-ного администрирования. Например, именно его при-меняет Red Hat в инструменте под названием anacondaдля обеспечения начальной установки своего дистри-бутива Linux.

Конечно, системные администраторы — натурывесьма консервативные, и потому я решил написать этустатью, показывающую, что Python действительно име-ет преимущества по сравнению с языком Perl и оболоч-

ками при решении как повседневных, так и одноразо-вых задач.

Python — интерпретируемый язык с развитыми вы-сокоуровневыми структурами данных, имеющий все не-обходимое для вызова функций POSIX-совместимых си-стем. Впрочем, Python является многоплатформеннымязыком, так что его можно с успехом использовать и, кпримеру, в среде Windows. Однако не буду долго гово-рить о происхождении и синтаксисе языка: об этом за-интересованный читатель узнает на http://python.ru илииз книги Сузи Р.А. Python. — СПб.: БХВ-Петербург,2002; а сразу перейду к делу.

Начнем с небольшого примера, в котором нам тре-буется установить права и принадлежность файлов, что-бы имена совпадали с именами пользователей в сис-теме (для простоты будем считать, что имена пользо-вателей доступны из файла /etc/passwd). Подобная за-дача может возникнуть, например, в каталоге с почто-выми ящиками, где каждый ящик должен принадлежатьсоответствующему его названию пользователю.

ВАДМИНИСТРИРОВАНИИСЕРВЕРА: ПОЧЕМУ БЫИ НЕТ?

РОМАН СУЗИ

������������ �

���������������

�������������� ���� �� ���������������� ����������!������������� �����������!���������"���"#$$���������"%$���������"&$����������'����������������� ��������� ��!

Page 31: 001 Системный Администратор 10 2002

29№1, октябрь 2002

администрирование

В самом начале мы импортируем модуль для рабо-ты с функциями ОС (os) и работы со строками (string).Перед началом цикла по строкам файла /etc/passwd сло-варь users пуст. В цикле по строкам файла /etc/passwdмы делаем следующее. Именем rec обозначаем кортежзначений записи passwd-файла. Мы знаем, что первоеполе этой записи — имя пользователя. Имя пользова-теля и станет ключом в словаре users. В качестве зна-чения для данного ключа мы берем приведенные к це-лому типу поля 2 и 3, соответствующие идентификато-рам пользователя и группы. Таким образом в первомцикле формируется отображение имени пользователяи его идентификаторов. Во втором цикле, по именамфайлов в текущем каталоге, пытаемся (try) найти вла-дельца файла, обращаясь к словарю users. Если это неудается, мы пишем на стандартный вывод соответству-ющую диагностику. В этом случае владельцем файластанет root. Последние две команды, думается, ясны ибез комментариев.

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

Для любознательных укажем и второй путь реше-ния, в котором используются «правильные» средства:

Здесь удалось добиться некоторого сокращенияпрограммы за счет использования функции getpwnamмодуля pwd стандартной библиотеки Python. Здесь так-же применена функция glob из одноименного модулядля получения списка файлов.

Для сравнения приведен неправильный пример по-добной же программы, написанный в оболочке bash.

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

файлов, содержащих в имени точку, пробел или дефисв начале!

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

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

В следующем примере мы рассмотрим еще одну ча-сто возникающую задачу: проверка работоспособнос-ти POP3-сервиса и отправка сообщения электроннойпочты в случае неудачи. Заметьте, что приведенныйпример одинаково хорошо подходит и для Unix, и дляNT.

С помощью конструктора объекта POP3-соединенияиз модуля poplib мы пытаемся установить соединениес POP3-сервером mymail. Если это не удается, мы дол-жны отправить о происшествии письмо наadmin@othermail. В этом нам поможет модуль smtplib иконструктор класса SMTP. Если и это не удается, про-сто выводится «нет связи». Заметьте, как легко в Pythonввести многострочный текст.

Надеемся, вы как минимум заинтересовались пред-лагаемым инструментом.

Таблица 1 поможет быстро найти аналоги распрост-раненных команд среди функций стандартной библио-теки языка Python. Перед использованием функции до-статочно импортировать соответствующий модуль.

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

������������ �

������������������

�������� �� �� ����������������������������� ������(��!�����!������������ ���������������)���!���������*'+,-.!����������������������������� � ����������#/##����� � ������������"%$�����"&$�

���������

��01�+.2,-.1-��134'�'516.�7.84,9�3,:1+;.-�-,<=>�'4'�?+,214�����������(����� ���@���� @�����@�����AA�� ������� �����@������� ����/##�@�������

������������ �

������������������

���!��������� BCB&������������ D������)���!������������������������!��������EFGB���� ������������� �������������H��������������H�� �����������I���!� ����H������G�!� ����H�� ������E��J���!�BCB&�������

B����������������&����������

��������� D��������)���!���������61-�39KL'�

�����!��������������������"����$�)���!���������*'+,-.!�����������������������#��#������������ � ����������#/##����� � ������������������

Page 32: 001 Системный Администратор 10 2002

30

администрирование

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

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

Разбираемый ниже пример не претендует на полно-ту решения проблемы спама, он решает частную зада-чу. Мы будем отслеживать лишь попытки массовых рас-сылок, в которых на один «mail from» следуют несколь-ко «rcpt to». Конечно, программу легко адаптировать идля другой ситуации, агрегируя данные по отправите-лям, получателям и так далее, получая портрет ситуа-ции на почтовом сервере. Следует заметить, что глядя

������������������������������������������� �����������

�� �� ������� �� ����������� ������������ ����

���������� �����������������

����� ��������� ��������������� �����

����������������� ������������������������

������������� ���� ���������������������

����� ����� �� ������������������������� �������������������

����� ����������������� ���

����� � �� ���������� � ������� ������

���� ��� �������� ����

�����!� ���������!��

������� � ��������� ���

���� ���������� ���

������������ �������������� ��������������� �����������������������

�"��� � ��������"���

��#������$�����%� ����� ��&������$��������%���

������$�����%� �� ��&������$��������%���

��# ������ ���������������

��������� �� ������������������� ��� ������������

����� ��� � ���� ���������� ����� ���

�&��������� ���&����������

� �����$�����%� � ��������������$��������%���

�� &�������� � ��&������������������������������ ��������������������

���� �����������

���#'�������� ���� ������������������

��������� ���� ��&������������������ ����������

������� � ����������� ���

���� ������������

������������ ���������� ������ ������ ��%���� ������

"��� � �������"���� ��

������� � �������������������

�������(�� � ��)�����������������������

(��������� � ��)�����������������������

*������ ��)�����������������+���������+���� �����

,������ � ��)�����������������+�������������+���� �����

Таблица 1

Page 33: 001 Системный Администратор 10 2002

31№1, октябрь 2002

администрирование

на «сырые» логи Sendmail не всегда можно увидетьпроблему. Во всяком случае, для этого требуется неко-торое напряжение глаз.

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

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

Задача распадается на две: сбор данных из лога вбазу данных и выборка из базы данных.

Построчно читаем из файла с логами и, в зависимо-сти от сработавшего шаблона, записываем в заранееоткрытые базы данных. Обратите внимание, что базаdate.db использует в качестве ключей как дату, так иидентификатор сессии. Последний делает ключ уни-кальным.

Заметим, что в Python логические операции or и andработают несколько необычно. Любой объект имеет такназываемое истинностное значение. Нули, пустые пос-ледовательности, объект None считаются «ложью», аостальные объекты -- истиной. В результате операцииA or B возвращается объект A, если он «истинен», а впротивном случае -- объект B. Именно поэтому имениm будет соответствовать результат первого успешногосравнения.

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

����������������M���������������"������$������"��������$�����"������$

���������������� ����������������������?,�>5,4<.6'N�������������������� �����������������������?,�>5,4<.6'N�O�?>3-.K

3-+,=.

� � � � ��������� ��� ����� ��� ����"!P$� ��� �E���� ��� ����� ���Q���� �R���!

�����������������-.='1�3,,2S16'K�61�'6-1+13>N-

��������������������!����9�L.9'3'5,3-'�,-�6.?+.9416'K���������� ��MR���������M���!���������"������M��$����"������M��$�T������T��U�����������!���������"������M��$��������T��U���������!�������"������M��$�������� � � � � � �"������M��$� �� ���� ����������M���� ���� ��

���� ������������� ����������"�����T�������M��$���������M�����M���� �������

� �������U� � �������U� � �������U� � �������

������������ ����V6.4'L�4,W.�E���������

������������������������������

���X��M����������������'5K�31+91+.��7'W>+'+>NS11�9�4,W.Y

���� ��������������!�����*,L:.6'1�Z[��������!��� ���R����������>:.4K15�3-.+>N�Z[���)���!��������'W6,+'+>15�'3=4N<16'K������������� ������������������������������������������=4N<!�L6.<16'1������������������ ����������':�3133''!�,-?+.9'-14\���������������� ������������':�3133''!�?,4><.-14'������������������� ���������':�3133''!�?,<-,9]8�Y,3-������������������ ����������9+15K�'�':�3133''!�':�3133''

^^^�_+'51+]�<1-]+1Y�Y.+.=-1+6]Y�34><.19!`��� aa� %#!%P!%b� ����� �������"Pc%#$!� �cdeCfg%##Pc%#!

�����h������H���� ��i�� ��j��a#&/bb�� ������#�� �����a�������h###�#a�%PaP�@�acb��k#@&#cb�k�#H��) ��i�� �����EFGB�������FG`�� ������"%a% %k a%c a%$

`��� aa� %#!%P!%b� ����� �������"Pc%#$!� �cdeCfg%##Pc%#!���h���H����� ��i�� ������##!##!#c�� ���a&&/bb�� �����f�����������������&%c/k���)�^^^

`��� aa� #P!#%!&a� ����� �������"ac#bk$!� �cd#%Qg%#ac#bk!�����h����RH��������� ��i�� ��j��&&lcc�� ������#�� �����a�������h%##%#kaa#&##%cM RM�%#kc�����MH���������!��� �������� �)i������EFGB��������FG`�������������a ���� ���"alP /c ak a%c$

`��� aa� #c!ak!%#� ����� �������"%k&%l$!� �cd&mng%#%k&%l!h�����H����� ��i � Q���� �R��^^^

�� Y.+.=-1+6]1� <.3-'� +1W>4K+6]Y� 9]+.;16'8� �?+17'=3�� Y,3-� '.:+13�

B� �� ��oBh����i �ab��� p����X��M������ �������q""#Ol$Tq$!�oBh������i"r!$T�!���p�X�����

s� �� ��������oBh�����i (�o!q"�oBh�����M�i To�q$�o��`� �� �qho�oBh����i"r���i$T�qio���+1W>4K+6]1�9]+.;16'K��3,,-91-3-9>NS'1�+.L6]5�34><.K5���aM��� �� �� ���������p�B���oBh�����i����p�`���� � (��

������oBh����i (���p�X���������%M��� �� �� ���������p�B���oBh�����i������p�`���

��j���oBh��j�i"#Ol$T��� (��p�s����p�X���������&M������� ���������p�B���oBh�����i������p�`���� (��p�s���

p�X���������PM��� �� �� ���������p�B��p�`��q q q � �oBh����iQ���

�R�����p�X������

���M����� �� ������ ���X"a$�� ����� � �� ,-=+]9.15� 7.84� 34,W,5

� ����a!�����������M���� ��������������������!����,26.+>;16�=,61t�7.84.!�9]Y,:�'L�t'=4.��������R����3+.96'9.15�3-+,=>�4,W.�3�u.24,6.5'���������aM�� ���� ������������%M�� ���� ������q������������&M�� ���� ������������PM�� ���� �����������!����134'�Y,-\�,:'6�u.24,6�3+.2,-.4!������������ ��������������?,4><.15�34,9.+\�W+>??�+1L>4\O

-.-.

Page 34: 001 Системный Администратор 10 2002

32

администрирование

в регулярных выражениях задаются через (?P<имя> ...).Взять из словаря значение по ключу можно не только спомощью словарь[ключ], но и с помощью метода get().В последнем случае можно задать значение «по умол-чанию», то есть значение, которое метод get() возвра-тит в случае отсутствия ключа в словаре.

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

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

Для нашей цели (выявление чрезмерных списковрассылки) данные удобно отсортировать по времени.Это легко сделать с ключами из базы date.db. По сутимы считываем все ключи этой базы в память (методkeys()) и сортируем их по возрастанию.

Здесь особо следует отметить функцию filter(). Этавстроенная функция применяет некоторую функцию (ар-гумент 1) к списку (аргумент 2). В нашем случае ис-пользуется our_filter, которая возвращает «истину» вслучае, когда ее аргумент содержит «@».

Составленная программа далека от совершенства,однако ее легко доработать в любом нужном направ-лении: добавить возможность обработки нескольких

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

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

Программисты на Python утверждают, что на этомязыке можно писать «со скоростью мысли», то есть, по-чти все время оставаясь в предметной области. Есливы этому не верите, попробуйте переписать приведен-ные программы с использованием стандартного Си илиJava. С другой стороны, приведенную задачу обычнорешают с помощью языка Perl. К сожалению, Perl вно-сит очень много синтаксического мусора, что подчасзначительно затеняет логику программы.

Основными преимуществами Python являются, намой взгляд:

� удобный и легко читаемый синтаксис� многоплатформенность� поддержка основных системных и сетевых протоко-

лов и форматов� большой набор библиотек� свободное распространение� дружелюбная поддержка в телеконференции

comp.lang.python� надежный и устойчивый интерпретатор

Все это делает Python отличным инструментом в ра-боте системного администратора.

������������ ����V6.4'L'+>15� 3,2+.66]1� :.66]1���

���������������������������

��,-=+]9.15�2.L]��������� �������� ������������������ ������ ������������������ ��������� ������������������ �������� ���������

��?,=.L]9.-\�-,4\=,�34><.'�,-?+.9416'K�i��vmF�?,4><.-14K5���!��vmF��������� ���X"a$��)���!��vmF���P

�R������� R���������?,4><.15�931�=4N<'�9�,:'6�3?'3,=�� 3,+-'+>15� �7.=-'<13='�� ?,� 9+1516'� � _+1612+1W.15� 3516,8

513Kt19�R��� ������

����M����M��� �� �� �������� (�����RH��������� ��AO������H�������� ��AH����� ������� ��AH ���P ���� ���qw��

���� ���M�������)�!�����x>6=t'K�:4K�7'4\-+.t''�?,4><.-1418������������H����)

��������M����M������R���!�������"����M����M��$����6.Y,:'5�':16-'7'=.-,+�3133''�����!���������������� ������"�$���U������3?'3,=�?,4><.-1418������21+15�-,4\=,�.:+13.�3�H���������������������M��������������������������"�$����,-?+.9'-14\������?,=.L]9.15����������������i��vmF�����������M����M�� ���� �������!���������������"�$����������������M����M��"!ab$����?1+9]1�ab�3'59,4,9�OO�:.-.�����������"�$���������������Oiq������������� J��������

�q�����������)���!����134'�9,L6'=4'�,u'2='��?+,?>3=.15�������

� �������U� � �������U� � �������

Page 35: 001 Системный Администратор 10 2002

ПРОГРАММИРОВАНИЕ

Page 36: 001 Системный Администратор 10 2002

РАБОТАСТЕКСТОМИЛИФИЛОСОФИЯPERL

ЕВГЕНИЙ КОНОВАЛОВ

Page 37: 001 Системный Администратор 10 2002

35№1, октябрь 2002

программирование

Вместо лирического вступления

На всякий случай автор искренне просит не рассмат-ривать эту статью как очередное «УРА» в честь наиболееразвитого и удобного, свободного, попросту приятного идаже замечательного языка для работы с текстом и про-граммирования в Web (разумеется, речь идет о Perl).

Сильным духом программистампосвящается...

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

Сначала несколько слов об истоках рассматриваемойпроблемы. Сегодня адаптация документов различныхформатов для внесения их в БД Web-сайта - занятие при-вычное во многих организациях, имеющих собственную«точку присутствия» в сети Интернет. Зачастую это свя-зано с возможностью простой реализации полнотексто-вого поиска в таблицах БД и простотой реализации меха-низмадоступа к информации.

Так или иначе, все выглядит достаточно просто и по-нятно, когда речь заходит о небольших объемах данных,особенно, если они подготавливаются централизованоодним-двумя сотрудниками. Сложности возникают приработе с документами больших размеров.{1} Что такжеможет осложняться острым желанием предоставить ад-министратору БД и многочисленным контент-менеджерамудобную методику для работы с данными.

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

ление пользователю возможности их раздельного про-смотра. Это связано с сегодняшней философией жизни вИнтернет, например, с «диалапными» скоростями досту-па (впрочем, не только с этим).

Подытоживая сказанное, Вашему вниманию представ-ляется задача, решенная в рамках разработки подсисте-мы информационного наполнения БД.

Исходные данные:� тип вносимой информации - HTML-код значительного

объема;� весь HTML-код заключен в едином документе;� документ необходимо разбить на составные части, ко-

торые размещаются в БД (с тем же успехом их можносохранить в файл).Основная трудность решения: в результате разбиения

документа необходимо получить фрагменты HTML-кода,имеющие корректную HTML-структуру. Такого рода кор-ректность подразумевает:� соответствие каждому начальному HTML-тегу завер-

шающего HTML-тега (для HTML-элементов, обязатель-но обозначаемых именно парой тегов);

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

Отправная точка: исходные данные вподробностях

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

Говоря коротко, необходимо иметь HTML-документ сгипертекстовым оглавлением (в оглавлении должны ис-пользоваться внутренние гиперссылки - то есть те, значе-ния атрибутов href которых начинаются со знака решетки«#»). Такой подход достаточно удобен. Теперь о том жесамом, но уже более подробно.

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

«Внутренняя гиперссылка» - ссылка, при нажатии накоторую выполняется переход на анкер (см. ниже), распо-ложенный в том же HTML-документе, в теле которого на-ходится и сама ссылка; значение атрибута HREF такойгиперссылки начинается со знака решетки #. Например:

«Анкер» - тег, размещаемый в том месте HTML-доку-мента, куда необходимо осуществить перемещение по на-жатию на внутреннюю гиперссылку. Например:

Есть два основных аспекта, которые легли воснову этой статьи.Первый - это периодически возникающаяперед большинством Web-программистовпроблема переноса тех или иных документовв базу данных (БД), используемую,например, при генерации страниц скриптами.Проблема эта из разряда концептуальных ирешается по-разному: в зависимости отрабочей среды, окружающей разработчикаплотным кольцом всевозможныхтребований, условий и согласований.Вторая идея, попавшая в фокус обсуждения -использование Perl для решениялюбопытной задачи, связанной с упомянутойвыше проблемой. Собственно об этом ипойдет речь в дальнейшем. (Примечание:данная статья, пожалуй, рассматриваетсяименно как посылка для обсуждения - иныеподходы не имеют и половины такой жепривлекательности.)

���������� ���������� �������������

���������� ����

«Если ты едешь тише - дольше ехать тебе. Если поспешишь, то неразглядишь идей»

«Начинать нужно с чего-то...», - и с этим трудно не согласиться.

Page 38: 001 Системный Администратор 10 2002

36

программирование

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

является внутренней ссылкой на анкер

«Оглавление» - гипертекстовое оглавление докумен-та, состоящее из внутренних гиперссылок.

«Пункт оглавления» - внутренняя гиперссылка, внут-ри тега которой заключен текст одного из пунктов содер-жания документа.

«Глава документа» или «Глава» - часть HTML-доку-мента, сопоставляемая одному из пунктов оглавления.

«Специальный анкер разметки» или «Анкер размет-ки» - анкер, на который ссылается один из пунктов оглав-ления. (Такой анкер разметки располагается непосред-ственно перед главой (обычно перед заглавием главы),которая соответствует пункту оглавления, ссылающему-ся на данный анкер разметки.)

«Документ» - текст HTML-документа (без оглавления).Далее, рассмотрим в качестве примера документа

обзор по материнским платам.Вообще говоря, в рассматриваемом случае оглавле-

ние в традиционном понимании имеет следующий вид:

Назовем это оглавление «Исходным оглавлением».Однако для корректного разбиения документа на гла-

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

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

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

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

Примечание: при программном анализе документазаголовочная часть (вплоть до тега <BODY>) и концевыетеги </HTML> и </BODY> не рассматриваются.

Замечание 1: в тексте документа не может быть болееодного анкера разметки с одним и тем же значением ат-рибута «NAME» (при этом количество анкеров разметкиравно числу пунктов оглавления).

Замечание 2: очевидно, что при разбиении на фраг-менты, первая глава будет содержать стартовые теги<TABLE>, <TR> и <TD> без концевых (завершающих) те-гов. Это явное нарушение HTML-структуры, которое мо-жет быть особенно неприятным при использовании SSI(если HTML-код главы будет включаться в состав основ-ной HTML-страницы средствами Web-сервера).

Программирование: идея, заложеннаяв основу

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

���������� ����

���������� ���������� ������������

���������� ���������� ���������������������� ���������� ���������!��"#� �������������� �$��$��!�%%� �#���#&� '��'%# ����� %##����(�% #�

)#��� # �������������� �*��*��+��,�-���.��#�������������� � �������������� �/��/���� ��� �.#� �%%� ����!+�%� � �����#0�#� ���

,�� ����

������ �������������� ���������!��"#� $��!�%%� �#���#&� '��'%# ����� %##����(�% #��)#��� # *��+��,�-���.��#�������������� � /���� ��� �.#� �%%� ����!+�%� � �����#0�#� ���� ,��

�����������1�#2�3�45678�9:;68<�=>?<@?5;AB����

��C�D�����3������(# E�� �� 3# � �%���������3����+F3G�

���������� ���������C�+D���C���C3��+���$���� ������������$���+��+���+�� ���F�C

�FDF��HHHHII������E�� ��� ��(#�&� ��.���,���&%��#����)�#.# '�����)�J#���&%� #������J��(���,�.��K�� K��� &L��(#�% ��# � ����E#���&%� #�������(#� �L������(#�&���E�� ��� �,�"#��� ' �#&�)�� �(# �� �����.#�� �J(��(��#,�.# ���)� &������) �&���% ��# � �����(# �%� � ��)�������F�C�

���������� ������������+���$���� ���������!��"#� ����$���+������F�C��FDF��HHHHII��!�L����� ���&#�)� �'������E�'����#J

����M#�J�,,������� �� ��(#�&��# ��% ��# � �����(� � #�����L� � ��� � � #.#�,#�� ��� �� � ���F�C��+���F�C�FDF����HHHH��% ��# � � #��������F�C���+���F�C�FDF��HHHHII��L�E���J�,,�����#�� ��#�����(#�%� � � # %�� �E,#�������#����K�����N�#�� �,�� ��# � �����O�����(#�&���E�� �L�(#� ��"#� L� ���#��(# #�� ���K #���.� �#�'��)��(#&���J���' ����F�C�

���������� �$����������+���$�!�%%� �#���#&� '��'%# ����� %##����(�% #��)#��� # ���

�$���+������F�C��FDF��HHHHII��������,'��(#������ � # %�� �E,#�)�

�.# �,,�%# )� &���#��)�'�� ��# "��%�N� ����#E��"O� ' �#&���.#��(#�#0� #&#,'� %##�'�% ��# � �J�,,�E#�)����� ,�J#��E'�,# %# )� &��K�����N�����&���

��#&� 'O����F�C�

���������� �*�������������+���$�+��,�-���.��#�������������� � ����$���+������F�C� �FDF��HHHHII��� � '��� ##L� �(#� ,��# �� �(�% #�

(�.#�E��,�-����������� � ���.��#�����%�# �

���������� �/����������+���$��� ��� �.#� �%%� ����!+�%� � �����#0�#� ���� ,�� ���

�$���+������F�C��FDF��HHHHII��C(#���&# �J(#��'���(�������� ��,,

&�,��%,#����%��-���%����� � �����E#�)� K���#��������J�'���(�.#�,,�� �.#�N(� ������),�%%'O� �%%� ������(#�&���E�� ��

��C3���C����C�+D����+F3G����C�D�

«Идея - базис алгоритма», - и так повсюду.

Page 39: 001 Системный Администратор 10 2002

37№1, октябрь 2002

программирование

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

Идея проста: анализ сводится к подсчету количествастартовых и завершающих тегов и сравнении полученныхвеличин, исправление обнаруженных ошибок заключает-ся в добавлении недостающих стартовых и завершающихтегов.

Остановимся на этом чуть подробнее. Суть заключа-ется в том, что первоначально для каждой главы из тех, накоторые разбивается документ подсчитывается число на-чальных и завершающих тегов (назовем их «Величина-1»и «Величина-2»). Затем при обнаружении несоответствиямежду этими значениями начинается итерационный поискнедостающего парного тега: последовательно перебира-ются последующие главы и для каждой такой главы к ве-личине-1 и величине-2 соответственно прибавляются чис-ла начальных и завершающих тегов этой главы. Условиемуспешного окончания поиска недостающего парного тегаявляется равенство величины-1 и величины-2.

Если назвать главу, в которой обнаружилось несоот-ветствие, стартовой (Главой итерационного поиска); главув которой был найден недостающий парный концевой тег -заключительной, а все главы между ними - промежуточ-ными, то процесс коррекции HTML-структуры глав можноописать достаточно просто. Необходимо дополнить стар-товую главу концевым HTML-тегом, заключительную гла-ву - стартовым HTML-тегом, промежуточные главы - стар-товым и концевым HTML-тегами.

Программирование: иерархия классов

При работе упор был сделан на методику объектно-ориентированного программирования. Именно это позво-лило использовать уже существующие классыHTML::Parser, предоставляющий методы для разбораSGML-документов (так же используется HTML::Filter - до-черний класс HTML::Parser).

Было разработано два класса: Manual_Cont_Parser иManual_Parser.

Manual_Cont_Parser наследуется от HTML::Filter, классзанимается обработкой оглавления (см. выше), разбираяего попунктно. Предоставляет методы:

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

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

Manual_Parser наследуется от HTML::Parser. Отвеча-ет за разбор документа и его разбиение на главы. Имен-но этому классу и будет уделено основное внимание.

Класс HTML::Parser обладает рядом методов. Ключе-выми являются методы parse($string) или parse_file($file),вызов одного из них инициирует работу по анализу доку-мента.

Еще два используемых метода - start($tag, $attr,

$attrseq, $origtext) и end($tag, $origtext). Первый из нихвызывается при обнаружении начального HTML-тега, пе-редаваемые ему параметры: $tag - имя тега, $attr - хэш сименем атрибута тега в качестве ключа и значением ат-рибута в качестве значения хэша, $attrseq - массив именатрибутов тега, $origtext - HTML-код тега. Второй методвыполняется при обнаружении завершающего HTML-тега:$tag - имя тега, $origtext - HTML-код тега.

В программе методы start и end перегружаются (за-мещаются). Именно в рамках этих процедур производит-ся потеговый анализ документа и собирается упомянутаявыше статистика, характеризующая его HTML-структуру.

Программирование: основныеструктуры данных

Речь идет о структурах данных объектов классаManual_Parser - в них накапливается статистика, позво-ляющая проанализировать HTML-структуру документа.

Существует три основные структуры данных:$Doc_Info, $Work_Container и массив @Pages_Info. Сразуже следует заметить, что речь идет о сложных, вложен-ных структурах данных. Их понимание играет ключевуюроль.

Каждый элемент массива @Pages_Info представляетсобой структуру данных, с элементами в виде скаляров,списков и хэшей, описывающих HTML-структуру однойглавы (замечание в рамках борьбы с несозвучностью на-званий и терминологии: под «Page» понимается HTML-страница, соответствующая главе).

«Структура структурной структуризации структурируетструктурную типизацию», - и все это не случайно.

Page 40: 001 Системный Администратор 10 2002

38

программирование

Программирование: алгоритмы работыи программный код

Ниже приведены прокомментированные строки кода,указываемые в приложении, использующем классыManual_Cont_Parser и Manual_Parser.

Создание объекта класса Manual_Cont_Parser:

Подготовка к анализу документа: разбор оглавлениядокумента, получение списка анкеров разметки:

Создание объекта класса Manual_Parser:

Анализ документа, разбор, корректировка и разбие-ние на главы:

Использование полученных результатов: внесение по-лученных глав в БД Web-подсистемы:

Подготовка к анализу HTML-документа

Первоначально объекту класса Manual _Cont_Parserпередается оглавление. Вызываются методы parse($text)или parse_file($file). Затем с помощью методаGet_Links_Hrefs получается результирующий список строк,каждая из которых содержит преобразованное значениеатрибута href одного из пунктов оглавления (преобразо-вание заключается в удалении символа «#», с которогоначинается значение данного атрибута). Затем строки по-лученного списка будут использоваться объектом классаManual_Parser для нахождения анкеров разметки в доку-менте.

P��K# 2��)����Q�RST�78U:68:U�N7V��;AW5O��C�K ����QXC�K YL�RST�78U:68:U�N7V��;AW5O��C�K 2!#12��K#����QXC�K 2!#12��K#YL�Z[\55�6=?A]578@=�78<U8=@^_�85>=@�@�9U5`5?<_�=`;=a�>?<@^����&2F)2C�K ����b��&2F)2C�K L�c<77A@L�6<W`=5�d;<]5;A5�-�9=UB`6=@^a�;=V5U�85><�@�e=6:V5;-

85L�`?B�6=8=U=>=��@�f?<@5�;5=[_=`AV=�`=[<@A8g�78<U8=@^a�85>���!�� �2C�K 2C�2�������QP!�� �2C�K 2C�2���YL�c<77A@L�6<W`=5�d;<]5;A5�-�9=UB`6=@^a�;=V5U�85><�@�e=6:V5;-

85L�`?B�6=8=U=>=�@�f?<@5�;5=[_=`AV=�`=[<@A8g��d<@5UT<h\Aa�85>������2C�K 2C�2�������QP���2C�K 2C�2���YL�RSTL�6?h]�_ST<�-�d;<]5;A5�<8UA[:8<�( #)�i;:8U5;;5a�fA95U-

77^?6AL�d;<]5;A5�_ST<�-�;=V5U�f?<@^��D���,2D��" ����XD���,2D��" L�RSTL�6?h]�_ST<�-�d;<]5;A5�<8UA[:8<�( #)�i;:8U5;;5a�fA95U-

77^?6A�;<�=`;:�Ad�f?<@L�d;<]5;A5�_ST<�-�;=V5U�f?<@^��D���,2D��" 2C�2��K# ����XD���,2D��" 2C�2��K# �YjRST�78U:68:UL�6?h]�_ST<�-�9=UB`6=@^a�;=V5U�85><�@�856:\5a

f?<@5�XC�K 2!#12��K#���Q�kVB�85><��C�K2��&#����bC�K2��&#L�l=UB`6=@^a�;=V5U�85><�@=�@75V�e=6:V5;85��C�K2��&2��23������bC�K2��&2��23���Yj

RST�78U:68:UL�6?h]�_ST<�-�AVB�N8A9O�85><�XC�K ���Q�m=?A]578@=�;<]<?g;^_��C�D-85>=@�`<;;=>=�8A9<�@�f?<@5��!�� �2C�K2��&����b!�� �2C�K2��&L�m=?A]578@=�d<6?h]A85?g;^_��C�D-85>=@�`<;;=>=�8A9<�@�f?<@5�����2C�K2��&����b���2C�K2��&�Yj

$Doc_Info представляет собой структуру данных, с эле-ментами в виде скаляров, списков и хэшей, описываю-щих документ вцелом.

b3��2��)����Q�RST�78U:68:U�N7V��;AW5O��C�K 2!#123������QXC�K 2!#123��YL�RST�78U:68:U�N7V��;AW5O��C�K ����QXC�K YLZ[\55�6=?A]578@=�78<U8=@^_�85>=@�@�9U5`5?<_�e=6:V5;8<���,,2!�� �2C�K 2��&����b�,,2!�� �2C�K 2��&L�Z[\55�6=?A]578@=�d<@5UT<h\A_�85>=@�@�9U5`5?<_�e=6:V5;8<���,,2���2C�K 2��&����b�,,2���2C�K 2��&L�R5TL�6?h]�_ST<�-�AVB�<;65U<L�d;<]5;A5�_5T<�-�;=V5U�f?<@^L

@�6=8=U=a�U<79=?=W5;�<;65U��D���,2���(� ����XD���,2���(� �Yj

RST�78U:68:UL�6?h]�_ST<�-�9=UB`6=@^a�;=V5U�85><�@�e=6:V5;85�XC�K 2!#123�����Q�kVB�85><��C�K2��&#����bC�K2��&#L��C�D-6=`�85><��C�K2F �K2C#0�����bC�K2F �K2C#0�L�n=V5U�85><�@�f?<@5��C�K2��&2��2��K#����bC�K2��&2��2��K#L�n=V5U�f?<@^L�@�6=8=U=a�;<a`5;�`<;;^a�85>��C�K2��K#2��&����bC�K2��K#2��&�Yj

bM� "2�������# �Q�i�S8:�95U5V5;;:h�d<;=7A87B�;=V5U�f?<@^L�@�6=8=U=a�;5`=78<-

58�d<@5UT<h\5>=�85><��f?<@<�78<;=@A87B�78<U8=@=a�`?B�A85U<oA-=;;=>=�9=A76<�8=a�f?<@^L�@�6=8=U=a�7=`5UWA87B�;5`=78<h\Aa�d<-@5UT<h\Aa�85>

��!�� �2��K#2��&����b!�� �2��K#2��&L

$Work_Container - структура, представляющая собойконтейнер «рабочих» данных, она используется для вре-менного хранения данных в процессе анализа.

�kVB�<;<?AdAU:5V=>=�85><��C�K2��&#����bC�K2��&#L�n=V5U�<;<?AdAU:5V=>=�85><�@�e=6:V5;85��C�K2��&2��23������bC�K2��&2��23��L�n=V5U�<;<?AdAU:5V=>=�85><�@�f?<@5��C�K2��&2��2��K#����bC�K2��&2��2��K#L�l5U5V5;;<B�`?B�9=`7]58<�=[\5>=�6=?A]578@<�78<U8=@^_��C�D-

85>=@�@�e=6:V5;85��!�� �2C�K2��&2C���,����b!�� �2C�K2��&2C���,L�l5U5V5;;<B�̀ ?B�9=`7]58<�=[\5>=�6=?A]578@<�d<@5UT<h\A_��C�D-

85>=@�@�e=6:V5;85�����2C�K2��&2C���,����b���2C�K2��&2C���,�Yj

� b���2����2�� # -�%� #Nb����#�� Oj�&'�P����#�� 2� #) ���b���2����2�� # -�p#�2D��" 2� #) j

&'�b���2�� # ��������,2�� # -��#JNqP����#�� 2� #) Oj

b���2�� # -��� # �2��K# 2��23+NOj

«Алгоритм - это, как минимум, четкая, осмысленная последователь-ность действий», - редкая женщина обладает даром алгоритма.

&'�b���2����2�� # ��������,2����2�� # -��#JNOj

b���2�� # -�%� #Nb3���&#��2C#0�Oj

Page 41: 001 Системный Администратор 10 2002

39№1, октябрь 2002

программирование

Анализ HTML-документа: тег за тегомДалее подробно комментируется программная реали-

зация решения описанной выше задачи. Приведенныйнаже программный код относится к классу Manual_Parser.

@Array - массив (инициализируется в конструкторе присоздании объекта), в котором содержатся имена анкеров.Разметки, полученные в виде результирующего списка настадии подготовки к анализу документа (см. ранее).

Процедура start() - замещает процедуру start() классаHTML::Parser, вызывается при нахождении стартового (на-чального) HTML-тега. Процедура работает со всем тек-стом документа, «физического» разбиения на главы наданном этапе не произодится - каждая глава рассматри-вается как составная часть документа.

�E� �� �Q�&'�b #,)��� (�)�j

l=?:]5;A5�9<U<V58U=@�85><�N=9A7<;A5�7V��U<;55O�&'�Nb��KL�b��� L�b��� #1L�b� �K�#0�O���P2j

�&'��PC#&%2����2���� ���PQb #,)-�Q����#�� 2���� YYj

lU=@5U6<r�@_=`A8�?A�;<a`5;;^a�78<U8=@^a�85>�@�79A7=6�85_85>=@L� `?B� 6=8=U^_� ;5� =[Bd<85?g;=� :6<d^@<8g� 9<U;^a� 6=;o5@=a85>

��)�NsNb #,)-�C�K2� 2�0�#%����2�(#�"Nb��KOOO�Q

�lU=@5U6<r�B@?B587B�?A�;<a`5;;^a�85>�>A95U77^?6=a�A?A����<;65U=V���)�Nb��K�#1�t�uO��Q���&'�bD� �2C�K2� 2����2� #)�Hje?B�6<W`=>=�AV5;A�v;65U<�w<dV586A���)� #��(�bC#&%�NP� �'OQ���lU=@5U6<r�;<a`5;;^a�85>�-��v;65U�w<dV586A�����)�Nb��� -�Qt��&#uY�#1�bC#&%�xx�b��� -�Qt��&#uY��#�tuO���i^78<@?5;A5�y?<>=@L�AdV5;5;AB�7]58]A6=@����Q

����z]58]A6�]A7?<�85>=@�@�f?<@5�NA;AoA<?AdAU:587B�@�6=;78-U:68=U5� 9UA� 7=d`<;AA� =[{568<O� -� d;<]5;A5� U<@;=� 9=UB`6=@=V:;=V5U:�N@�f?<@5O�<;<?AdAU:5V=>=�85><

�����b #,)-�QC�K2��&2��2�� 2��K#Y�Hj

�z]58]A6�]A7?<�78U<;Ao�NA;AoA<?AdAU:587B�@�6=;78U:68=U5�9UA7=d`<;AA�=[{568<O�-�d;<]5;A5�U<@;=�9=UB`6=@=V:�;=V5U:�856:\5a<;<?AdAU:5V=a�f?<@^

�����b #,)-�Q�� #��2��K#Y||j

�����bD� �2C�K2� 2����2� #)��j�����,� �j����Y���lU=@5U6<r�;<a`5;;^a�85>�-�>A95U77^?6<�;<�=`;:�Ad�f?<@����#, �)�Nb��� -�Qt( #)uY�#1�}���NtuL~~LbC#&%OO����Q� � � � z=_U<;A8g� @� 78U:68:U5� `<;;^5� =� ;<a`5;;=a� i;:8U5;;5a

fA95U77^?65�;<�=`;:�Ad�f?<@�����&'�bC#&%����b��� -�Qt( #)uYj�����bC#&%����� ���j� � � � � b #,)-�Q��K# 2��)�Y�b #,)-�Q�� #��2��K#Y�-

�QD���,2D��" 2C�2��K# YQbC#&%�Y�b #,)-�Q�� #��2��K#Yj�����bD� �2C�K2� 2����2� #)��j����Y���Y

��lU=@5U6<r�9=7?5`;Aa�;<a`5;;^a�85>�-�;5�v;65U�w<dV586A�A;5�i;:8U5;;BB�fA95U77^?6<�;<�=`;:�Ad�f?<@

����)�NbD� �2C�K2� 2����2� #)��HO���Q

���lU=@5U6<r�;<a`5;;^a�85>�-��<;65U�����)�Nb��� -�Qt��&#uY��#�tuO����Q� � � � � b #,)-�Q3��2��)�Y-�QD���,2���(� YQb��� -

�Qt��&#uYY�b #,)-�Q�� #��2��K#Yj����Y

���lU=@5U6<r�;<a`5;;^a�85>�-�i;:8U5;;BB�fA95U77^?6<�����)�Nb��� -�Qt( #)uY��������O����Q�����&'�bC#&%����b��� -�Qt( #)uYj�����bC#&%����� ���j� � � � � b #,)-�Q��K# 2��)�Y�b #,)-�Q�� #��2��K#Y�-

�QD���,2D��" YQbC#&%�Y�b #,)-�Q�� #��2��K#Yj

����Y���Y��Y

�Z[;=@?5;A5�78<8A78A6A�9=�;<a`5;;=V:�85>:�@�78U:68:U5�`<;-;^_�9=�856:\5a�f?<@5

� � b #,)-�Q��K# 2��)�Y�b #,)-�Q�� #��2��K#Y�-�Q��&2F)2C�K Y||j

��b #,)-�Q��K# 2��)�Y�b #,)-�Q�� #��2��K#Y�-�QC�K YQ�b��KY-�Q!�� �2C�K2��&Y||j

� � b #,)-�Q��K# 2��)�Y�b #,)-�Q�� #��2��K#Y�-�QC�K 2!#12��K#YQb #,)-�QC�K2��&2��2�� 2��K#YY-�QC�K2��&#Y�b��Kj

� � b #,)-�Q��K# 2��)�Y�b #,)-�Q�� #��2��K#Y�-�QC�K 2!#12��K#YQb #,)-�QC�K2��&2��2�� 2��K#YY-�QC�K2��&2��23��Y���b #,)-�QC�K2��&2��23��Yj

�Z[;=@?5;A5�78<8A78A6A�9=�;<a`5;;=V:�85>:�@�78U:68:U5�`<;-;^_�9=�e=6:V5;8:

��b #,)-�Q3��2��)�Y-�QC�K YQ�b��KY-�Q!�� �2C�K2��&Y||j��b #,)-�Q3��2��)�Y-�QC�K 2!#123��YQb #,)-�QC�K2��&2��23��YY-

�QC�K2��&#Y�b��Kj��b #,)-�Q3��2��)�Y-�QC�K 2!#123��YQb #,)-�QC�K2��&2��23��YY-

�QC�K2F �K2C#0�Y�b� �K�#0�j��b #,)-�Q3��2��)�Y-�QC�K 2!#123��YQb #,)-�QC�K2��&2��23��YY-

�QC�K2��&2��2��K#Y�b #,)-�QC�K2��&2��2�� 2��K#Yj��b #,)-�Q3��2��)�Y-�QC�K 2!#123��YQb #,)-�QC�K2��&2��23��YY-

�QC�K2��K#2��&Y�b #,)-�Q�� #��2��K#Yj��b #,)-�Q3��2��)�Y-�Q�,,2!�� �2C�K 2��&Y||j

��b #,)-�QC�K2��&2��2�� 2��K#Y||j�z]58]A6�]A7?<�85>=@�@`=6:V5;85�NA;AoA<?AdAU:587B�@�6=;78-

U:68=U5�9UA�7=d`<;AA�=[{568<O��b #,)-�QC�K2��&2��23��Y||j�YY

Page 42: 001 Системный Администратор 10 2002

40

программирование

Процедура end() - замещает процедуру end() классаHTML::Parser, вызывается при нахождении стартового (на-чального) HTML-тега. Процедура работает со всем тек-стом документа, «физического» разбиения на главы наданном этапе не произодится - каждая глава рассматри-вается как составная часть документа.

Процедура _Separate_Manual_Into_Pages() - использу-ется для выборки глав из HTML-кода документа и сохране-ния их в массиве в виде отдельных текстовых фрагментов.При этом их HTML-структура не откорректирована.

Для выборки требуемых фрагментов HTML-кода ис-пользуются регулярные выражения. Синтаксис выраже-ния зависит от того, какая именно глава должна быть выб-рана (первая, последняя или любая из промежуточных).

Процедура Generate_Manual_Parts() - в данной про-цедуре реализован анализ статистики , собранной ранеепо главам и документу. На основании анализа корректи-руется HTML-структура глав.

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

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

До тех пор пока не будет найден парный концевой тегили не будут просмотрены все главы:

�E�p#�# ��#2�����,2�� � Q�&'�b #,)��� (�)�j

l=?:]5;A5�f?<@�@�@A`5�=8`5?g;^_�yU<>V5;8=@��C�D-6=`<�A�7=-_U<;5;A5�A_�@�V<77A@

� &'� P�����,2�� � �b #,)-�2!#%� ��#2�����,2����2��K# Nb�����,2C#0�Oj

k;AoA<?Ad<oAB�7]58]A6<�78U<;Ao�&'�b�� #��2��K#2��&�Hj

e?B�6<W`=a�9=?:]5;;=a�f?<@^�)� �N&'�b��Hj�b���b�����,2�� � j�b�||O�Q��b�� #��2��K#2��&�b�j

�e?B�6<W`=>=�85><�<;<?AdAU:5V=a�f?<@^��)� �N&'�b}�Hj�b}�b #,)-�Q��K# 2��)�Y�b��-�Q��&2F)2C�K Yj

b}||O��Q���<9=V;A8g�AVB�N8A9O�85><�@�b�� #��2C�K2��&#� � � &'� b�� #��2C�K2��&#� �� b #,)-�Q��K# 2��)�Y�b��-

�QC�K 2!#12��K#YQb}Y-�QC�K2��&#Yj

��lU=@5U6<r�`?B�85>=@�d<9=V;5;;=>=�8A9<�6=?A]578@=�78<U8=-@^a�A�6=;o5@^_�85>=@�@�f?<@5�;5�7=@9<`<58

����)�Nb #,)-�Q��K# 2��)�Y�b��-�QC�K YQb�� #��2C�K2��&#Y-�Q!�� �2C�K2��&Y� s�� b #,)-�Q��K# 2��)�Y�b��-�QC�K YQb�� #��2C�K2��&#Y-�Q���2C�K2��&YO

���Q���l=V58A8g�856:\:h�78U<;Ao:�6<6�78<U8=@:h�@�U<V6<_�A85U<-

oA=;;=>=�9=A76<�9<U;=>=�d<@5UT<h\5>=�85><����b #,)-�QM� "2�������# Y-�Q!�� �2��K#2��&Y�b�j

�E�#��Q�&'�b #,)��� (�)�jl=?:]5;A5�9<U<V58U=@�85><�N=9A7<;A5�7V��U<;55O�Nb��KL�b� �K�#0�O�P2j

lU=@5U6<r�@_=`A8�?A�;<a`5;;^a�78<U8=@^a�85>�@�79A7=6�85_85>=@L� `?B� 6=8=U^_� ;5� =[Bd<85?g;=� :6<d^@<8g� 9<U;^a� 6=;o5@=a85>

��)�NsNb #,)-�C�K2� 2�0�#%����2�(#�"Nb��KOOO�Q�Z[;=@?5;A5�78<8A78A6A�9=�6=;o5@^V��C�D-85><V�`?B�856:\5a

f?<@^��b #,)-�Q��K# 2��)�Y�b #,)-�Q�� #��2��K#Y�-�QC�K YQ�b��KY-

�Q���2C�K2��&Y||j

� Z[;=@?5;A5� 78<8A78A6A� 9=� 6=;o5@^V� �C�D-85><V� `?B� @75>=e=6:V5;8<

��b #,)-�Q3��2��)�Y-�QC�K YQ�b��KY-�Q���2C�K2��&Y||j��b #,)-�Q3��2��)�Y-�Q�,,2���2C�K 2��&Y||j�Y

Y

b #,)-�QM� "2�������# Y-�Q!�� �2C�K2��&2C���,Y� �� b #,)-�Q��K# 2��)�Y�b��-�QC�K YQb�� #��2C�K2��&#Y-�Q!�� �2C�K2��&Yj

�E�2!#%� ��#2�����,2����2��K# Q�&'�b #,)��� (�)�j

�&'�b�����,2C#0���� (�)�j

�&'�P�����,2�� � j

�)� �Nb��-�j�b���b� �'j�b�||O�Q��lU=@5U6<r�@^[AU<5V�Ad�e=6:V5;8<�95U@:h�f?<@:���)Nb���-�O��Q���b�����,2C#0������N��O�q ��q |��&#��b� �'�b�|���q ���

� j

���b�����,2�� � �b�|���b�j��Y��lU=@5U6<r�@^[AU<5V�Ad�e=6:V5;8<�9U=V5W:8=];:h�f?<@:��#, �)�Nb��b� �'O��Q���b�����,2C#0������N�q ��q |��&#��b� �'�b���q �����q �q�

�q ����O�q ��q |��&#��b� �'�b�|���q ���� j

���b�����,2�� � �b�|���b�j��Y��lU=@5U6<r�@^[AU<5V�Ad�e=6:V5;8<�9=7?5`;hh�f?<@:��#, #��Q���b�����,2C#0������N�q ��q |��&#��b� �'�b���q �����q �q�

�q ����O�� j

���b�����,2�� � �b�|���b�j��Y�Y

�i=d@U<\<58�V<77A@L�6<W`^a�S?5V5;8�6=8=U=>=�7=`5UWA8�85678=`;=a�Ad�f?<@

� #�� ��P�����,2�� � jY

� � b #,)-�QM� "2�������# Y-�Q���2C�K2��&2C���,Y� �� b #,)-�Q��K# 2��)�Y�b��-�QC�K YQb�� #��2C�K2��&#Y-�Q���2C�K2��&Yj

�Q���2C�K2��&Yj����Y���lU=@5U6<r�6=;o5@=a�85>�[^?�;<a`5;�����)�Nb�� #��2��K#2��&����b�����,2�� � O����Q����e?B�@75_�f?<@�:]<78@=@<@TA_�@�A85<UoA=;;=V�9=A765�9<U-

;=>=�85><�����)� �Nb"�b #,)-�QM� "2�������# Y-�Q!�� �2��K#2��&Yj�b"

���b�� #��2��K#2��&j�b"||O�����Q������e?B�78<U8=@=a�f?<@^�A85U<oA=;;=>=�9=A76<�������)�Nb"����b #,)-�QM� "2�������# Y-�Q!�� �2��K#2��&YO������Q�������<9=V;A8g�9=UB`6=@^a�;=V5U�85><�@�e=6:V5;85L�`?B�6=-

8=U=>=�;5=[_=`AV=�`=[<@A8g�9<U;^a�6=;o5@=a�85>�@�f?<@5

Page 43: 001 Системный Администратор 10 2002

41№1, октябрь 2002

программирование

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

Примечание: если ограничиться таким способом при-менения элементов Local_Links и Local_Links_To_Pages изструктуры данных Pages_Info (см. ранее), то вместо хэ-шей могут быть использованы обычные списки.

Вместо заключения

Возможности Perl по работе с текстом действительновелики. Это прописная истина, и в ней можно убеждатьсяснова и снова.

{1} Хранение крупных страниц целиком в БД - это, по-жалуй, не всегда является оптимальным решением. Иног-да гораздо приятнее иметь структурированный HTML-ар-хив в файлах на диске, а для удобства поиска размещатьрезультаты его индексирования в БД.

�������%� (�NPQb #,)-�Q��K# 2��)�Y�b"�-�Q���2C�K 2C�2���YYLb #,)-�QM� "2�������# Y-�QC�K2��&2��23��YOj

�������b #,)-�Q��K# 2��)�Y�b"�-�QC�K YQb�� #��2C�K2��&#Y-�Q���2C�K2��&Y||j

� � � � � � � b #,)-�Q3��2��)�Y-�QC�K YQb�� #��2C�K2��&#Y-�Q���2C�K2��&Y||j

������Y������e?B�d<6?h]A85?g;=a�f?<@^�A85U<oA=;;=>=�9=A76<������#, �)�Nb"����b�� #��2��K#2��&O������Q�������<9=V;A8g�9=UB`6=@^a�;=V5U�85><�@�e=6:V5;85L�`?B�6=-

8=U=>=�;5=[_=`AV=�`=[<@A8g�9<U;^a�78<U8=@^a�85>�@�f?<@5�������%� (�NPQb #,)-�Q��K# 2��)�Y�b"�-�Q!�� �2C�K 2C�2���YYL

b #,)-�QM� "2�������# Y-�QC�K2��&2��23��YOj� � � � � � � b #,)-�Q3��2��)�Y-�QC�K YQb�� #��2C�K2��&#Y-

�Q!�� �2C�K2��&Y||j�������b #,)-�Q��K# 2��)�Y�b"�-�QC�K YQb�� #��2C�K2��&#Y-

�Q!�� �2C�K2��&Y||j������Y������e?B�9U=V5W:8=];^_�f?<@�A85U<oA=;;=>=�9=A76<������#, #������Q�������<9=V;A8g�9=UB`6=@^a�;=V5U�85><�@�e=6:V5;85L�78<U8=-

@^a�A�6=;o5@=a�85>A�6=8=U>=�[:`:8�`=[<@?5;^�@�9U=V5W:8=];:h78U<;Ao:

�������%� (�NPQb #,)-�Q��K# 2��)�Y�b"�-�Q!�� �2C�K 2C�2���YYLb #,)-�QM� "2�������# Y-�QC�K2��&2��23��YOj

� � � � � � � b #,)-�Q3��2��)�Y-�QC�K YQb�� #��2C�K2��&#Y-�Q!�� �2C�K2��&Y||j

�������b #,)-�Q��K# 2��)�Y�b"�-�QC�K YQb�� #��2C�K2��&#Y-�Q!�� �2C�K2��&Y||j

�������%� (�NPQb #,)-�Q��K# 2��)�Y�b"�-�Q���2C�K 2C�2���YYLb #,)-�QM� "2�������# Y-�QC�K2��&2��23��YOj

� � � � � � � b #,)-�Q3��2��)�Y-�QC�K YQb�� #��2C�K2��&#Y-�Q���2C�K2��&Y||j

�������b #,)-�Q��K# 2��)�Y�b"�-�QC�K YQb�� #��2C�K2��&#Y-�Q���2C�K2��&Y||j

������Y�����Y����Y���Y��Y�Y�e?B�@75_�f?<@�)� �N&'�b��Hj�b���b�����,2�� � j�b�||O�i^9=?;A8g�`=[<@?5;A5�;5`=78<h\A_�78<U8=@^_�A�6=;o5@^_�85-

>=@�N6=UU568AU=@6<��C�D-78U:68:U^O�Q��PQb #,)-�Q��K# 2��)�Y�b��-�Q!�� �2C�K 2C�2���YY�� � ��QbE

����b�Y�PQb #,)-�Q��K# 2��)�Y�b��-�Q!�� �2C�K 2C�2���YYj��PQb #,)-�Q��K# 2��)�Y�b��-�Q���2C�K 2C�2���YY��� � ��QbE

����b�Y�PQb #,)-�Q��K# 2��)�Y�b��-�Q���2C�K 2C�2���YYj���e=[<@A8g�78<U8=@^5�85>A� � )� #��(� &'� b.�,�#� NPQb #,)-�Q��K# 2��)�Y�b��-

�Q!�� �2C�K 2C�2���YYO��Q� � � b�����,2�� � �b���}���� NtuL� b #,)-�Q3��2��)�Y-

�QC�K 2!#123��YQb.�,�#Y-�QC�K2F �K2C#0�YL� b�����,2�� � �b��Oj��Y

��e=[<@A8g�6=;o5@^5�85>A� � )� #��(� &'� b.�,�#� NPQb #,)-�Q��K# 2��)�Y�b��-

�Q���2C�K 2C�2���YYO��Q� � � b�����,2�� � �b���b�����,2�� � �b���~��~�b #,)-

�Q3��2��)�Y-�QC�K 2!#123��YQb.�,�#Y-�QC�K2��&#Y�~�~j��Y�Y�i5U;:8g�f?<@^�7�=86=UU568AU=@<;;=a��C�D-78U:68:U=a� #�� ��P�����,2�� � jY

�m=UU568AU=@6<�i;:8U5;;A_�fA95U77^?=6�;<�f?<@^� )� #��(� b"#'� N"#' � XQb #,)-�Q��K# 2��)�Y�b��-

�QD���,2D��" 2C�2��K# YYO

�Q� � b�����,2�� � �b��� ��� �

N�q ���q Q�Y���( #)q ���q ���Ob"#'N��q �����O�b�78U=6<2(��%-d<9U=7<2:6<d^@<h\<B2� 9:8g2728=];=78gh2`=2`=6:V5;8<x%�K#�b�b��� j

�Y

�m=UU568AU=@6<�9U=]A_�i;:8U5;;A_�fA95U77^?=6�)� #��(�b"#'�N"#' �XQb #,)-�Q��K# 2��)�Y�b��-�QD���,2D��" YYO�Q� � b�����,2�� � �b��� ��� �

N�q ���q Q�Y���( #)q ���q ���ONb"#'�q �����O�b�78U=6<2(��%-d<9U=7<2:6<d^@<h\<B2�9:8g2728=];=78gh2`=2`=6:V5;8<x%�K#�b #,)-�Q3��2��)�Y-�QD���,2���(� YQb"#'Yb��� j

�Y

Page 44: 001 Системный Администратор 10 2002

42

программирование

ИСПОЛЬЗОВАНИЕ ПАМЯТИ В PERL ПРИ РАБОТЕ СБОЛЬШИМИ СТРОКАМИ

Обычно при программировании вPerl не приходится задумываться орасходе памяти. Этот язык содержитдостаточно качественную системусборки мусора. Кроме того, при ис-полнении Perl-программ как обыч-ных CGI-сценариев, с запуском ин-терпретатора Perl на каждое обра-щение к скрипту, вся использован-ная память гарантированно осво-бождается при завершении скрипта.

Но если Perl-скрипт обрабатыва-ет действительно большие дан-ные, — скажем, мегабайтные тексто-вые файлы — проблема разумногоиспользования памяти может статьдостаточно актуальной. Особенноэто важно, если скрипт исполняетсяпод управлением mod_perl или ана-логичной среды. Если всецело поло-житься на встроенный сборщик му-сора, может неожиданно оказаться,что процессы Web-сервера, исполня-ющие скрипты с помощью mod_perl,с каждым вызовом начинают зани-мать все больше памяти - вплоть додесятков мегабайт, постепенно по-глощая всю свободную RAM.

Я столкнулся с этой проблемой,когда реализовывал под mod_perl

сложный скрипт, предназначенныйдля обработки и парсинга произ-вольных HTML-страниц. Основнымтипом данных в скрипте были обыч-ные текстовые строки. Поначалу яобращался со строками очень сво-бодно, как это и принято в Perl и по-добных языках, не задумываясьпользовался функцией substr; конка-тенацией строк; регулярными выра-жениями; писал функции, возвраща-ющие в результате строку (HTML-текст Web-страницы), и т.п. Приве-ло это к тому, что типичный HTTPD-процесс с mod_perl'ом (Web-серверApache на Unix) тратил только на об-рабатываемые данные в среднемнесколько мегабайт. Это при том,что типичный размер HTML-страни-цы, которую следовало обработать,составлял всего 20-30 KB. А когда япопробовал "пропустить" через своюпрограмму 10-мегабайтный HTML -HTTPD-процесс "съел" 100 MB. Приэтом возникало впечатление утечкипамяти - процессы, по мере своей"жизни", занимали все больше ибольше обьема памяти.

В процессе тестирования и экс-периментов я выявил общие пробле-

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

Результаты своих исследованийя предлагаю вашему вниманию.

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

ПРОБЛЕМА I

Свободное употребление Perl-средств для работы со строками -regexp'ов, substr, конкатенаций типа$a.$b или "$a$b" - приводит к порож-дению лишних копий строки, т.е.там, где по логике вещей алгоритмудолжно хватить 2 MB, будет потра-чено 5 или 10 MB.

ПРОБЛЕМА II

Если не предпринять специаль-ных усилий, то после завершенияPerl-функции рабочая память, израс-ходованная в этой функции, НЕ БУ-ДЕТ освобождена! (Ситуация совер-

ЭФФЕКТИВНОЕ

ДАНИИЛ АЛИЕВСКИЙ

Page 45: 001 Системный Администратор 10 2002

43№1, октябрь 2002

программирование

шенно отличная от традиционнойпрактики в языках без сборки мусо-ра типа C++ или Pascal, когда все ра-бочие переменные, созданные внут-ри функции, уничтожаются при вы-ходе из функции.)

Это не так важно в обычном CGI-скрипте, исполняемом внешним ин-терпретатором Perl. По завершениискрипта процесс будет полностьюуничтожен вместе со всей своей па-мятью. Но в mod_perl или FastCGI,или в независимых приложениях,или серверах на Perl это очень су-щественно.

Обратите внимание - описаннаяпроблема НЕ ЕСТЬ истинная утеч-ка памяти. Встроенный сборщик му-сора действительно обеспечиваетутилизацию ненужных переменных.Просто он делает это не совсем так,как можно было бы ожидать. А имен-но: занятая память будет использо-вана повторно ПРИ СЛЕДУЮЩЕМВЫЗОВЕ той же самой функции, т.е.многократные повторные вызовыфункции не будут приводить к посте-пенному исчерпанию RAM - явле-нию, которое традиционно называ-ется утечкой памяти. Зато много-кратные вызовы приведут к друго-му: со временем будет занят наи-больший объем памяти из всех, ко-торые были нужны при различныхвариантах вызова этой функции. Вмоем случае, после того как моиPerl-функции один раз обработалиHTML-страницу размером 10 MB исоответствующий процесс сmod_perl "съел" 100 MB, он так и про-должал всегда занимать 100 MB,хотя все последующие обрабатыва-емые страницы были небольшими.Внешне такое поведение очень по-хоже на утечку - объем памяти, за-нятый процессом, никогда не умень-шается, но постепенно медленноувеличивается - по мере того какэтому процессу случайно попадают-ся данные все большего размера.

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

1.Как завести внутрифункции большую временнуютекстовую переменную, аперед выходом из функцииосвободить память из-поднее?Неправильное решение:

Правильное решение - добавитьперед выходом вызов undef:

Вызов undef освободит память, за-нятую переменной $text. Без такоговызова получаем общую проблему II).

2.Функция должна создатьбольшую строку и вернуть еев результате.Неправильное решение:

Такой Perl-код "съест" не 1 мега-байт, действительно необходимыйдля сохранения переменной $v, а 2мегабайта. Лишний мегабайт будетзанят интерпертатором Perl при вы-числении строкового выражения "a()"для последующего копирования этихданных в переменную $v.

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

Правильное решение - функциядолжна вернуть ссылку на созданнуюбольшую строку:

Такой код "съест" только 1 мега-байт, который освободится при вызо-ве undef.

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

если строка $text потенциально можетбыть большой (десятки килобайт илибольше).

3.Как передать большуюстроку в функцию?Неправильное решение:

В этом примере общей проблемы IIнет, но память расходуется напрасно.Оператор присваивания $text= $_[0]расходует второй мегабайт под копию$text переменной $_[0] (который осво-бождается в конце вызовом "undef").

Если есть возможность, лучше ра-ботать непосредственно с $_[0] - т.е.с алиасом внешней переменной. Аеще лучше - нагляднее - всегда пере-давать большие строки по ссылке.

Предлагаемое правильное реше-ние:

4.Как выполнитьконкатенацию несколькихстрок, одна из которыхможет быть очень большой?Неправильное решение:

или

������������� ����������������������������������� �!"�#������$�%����

�&

������������� ����������������������������������� �!"�#����'(��# �� )*+�,-"� -.� /0123--4� (�!,(�5�67�84'9 ��#���:-2�"0#�����) �"� -9!#2-��#)�6��,- '(�"8 ;�-.6(�,�����2�2�< ��(��-#+�6,- '#��# !2�)*"-�(!�!"!11*"-�)�=>>�-�?��@���

�&

�������������� ��������������������������������������A���

�&����� ���������� �!"�#���

������������� �����������������������������������������

�&����� ���������� �!"�#���

���� �����A���

���$�%����'�#)���B,�!"�(�"8 ;4�� )!6,!110C�/0123-!D��

�������������� �EFGH��'(���"! ��EFGH�#�,!�B- �# ��20�,5-1�D���������� �!"�#�������$�%����

�&������ ��������������������������������������

������������� �EFGH��'(���"! ��EFGH�#�,!�B- �IIJKLM�1��# ��20����� �!"�#����

�&������ ����������������������������������A����

�����N�� ��������

������N�� ��������

Page 46: 001 Системный Администратор 10 2002

44

программирование

Если строка $text велика, то подоб-ный код "съест" память, которуюнельзя освободить (см. задачу 2).

Правильное решение - конкатени-ровать по очереди:

5.Как удалить/заместитьнебольшую подстроку вочень большой строке?Неправильное решение:

Такой код потратит лишний нео-свобождаемый мегабайт при вычис-лении выражения substr($text,10) - см.задачу 2.

Правильное решение - использо-вать так называемую "магию lvalue":

Правда, в документации написано,что Perl 5.004 в этом случае работалнеэффективно. Но начиная с Perl5.005 это работает прекрасно: лишняяпамять не расходуется.

Эквивалентное правильное реше-ние - использовать 4-й параметрsubstr:

Но если предыдущий вариант вPerl 5.004 работает неэффективно, тотакой вариант в Perl 5.004 вообще нескомпилируется.

6.Как выделить в большойстроке большую подстроку?Скажем, как в мегабайтнойстроке выделитьполумегабайтную подстроку,начиная со смещения100,000?По описанным выше причинам сле-

дующий очевидный код неправилен:

В таком решении при вычислении"substr($text,100000,500000)" расходу-ются лишние полмегабайта, которыевпоследствии невозможно освободить.

Для этой задачи я не нашел крат-

кого и изящного решения. Возможныйкорректный подход использует следу-ющую функцию substrlarge:

Если нужно выделить сравнитель-но небольшой фрагмент исходнойстроки (в данной реализации - мень-ше половины общей длины), то нуж-ный фрагмент конструируется циклом,блоками по 32 KB. Потеря памяти приэтом составляет порядка 32 KB -столько расходует вычисление выра-жения "substr($_[0],...)" внутри цикла.

Если же требуется получить боль-шой фрагмент - больше половиныисходной строки - то используетсяиной, более быстрый алгоритм. Со-здается полная копия исходной стро-ки, после чего у нее обрезаются ко-нец и начало, как описано в задаче 5.При этом временно занимается па-мять под целую копию, но затем - приобрезании - занятый объем уменьша-ется. Так как требуемый объем памя-ти под конечный результат в даннойветке сравним с размером полнойкопии, то кратковременный расходпамяти под полную копию представ-ляется разумной платой за более вы-сокую скорость.

Обратите внимание: функцияsubstrlarge работает непосредственнос аргументом $_[0], не копируя его вовременную переменную - как этообычно делается в начале Perl-функ-ций. Копирование типа "my $s= $_[0]"

привело бы к напрасному расходу па-мяти под лишнюю копию исходнойстроки (см. также задачу 3).

С использованием функцииsubstrlarge правильное решение будеттаким:

7.При использованиирегулярных выражений, сбольшой строкой нельзягенерировать переменные$1,$2 и пр. Скажем,следующий коднеэффективен:

Хотя от этого регулярного выраже-ния нам требуется, очевидно, толькопрефикс строки $1, который можетбыть и небольшим, Perl все равно за-полнит переменные $&, $` и $'. А однаиз них будет большой - сравнимой ссамой $text. Причем память из-подэтих переменных автоматически неосвободится.

Здесь единственное известноемне правильное решение - избегатьприменения регулярных выражений кпотенциально большим строкам. Вданном случае можно было написатьцикл поиска пары переводов строкина основе вызовов функции index.

Можно также пользоваться "стати-ческими" регулярными выражениями -не использующими скобок (или ис-пользующими только (?:...) ). Такиерегулярные выражения не заполняютпеременных $1,$2,...,$&,$`,$' и соответ-ственно не расходуют много памяти.

8.Нужно прочитать из файлаили сокета большой текст.Типичное решение выглядит при-

мерно так:

Хотя на вид этот код вполне акку-ратный и следует приведенным выше

������N�� ������N��� �������N��� ���

������ ����������������������������������������4G4�G� ����

����������������� '� 6� O������ �� ��%����@�� P������EFGH4EF�H4EFQH�� '� ��$� $P���R� ���� ����� ���P��� NS��������������������'�T���U��V� '� � ��� U� �������������4WGG4�GGGGGG���'���P����@�P���N�S�U���'����$�%�U���'�6����������@P�P��@����X��������%P��'������ ���������4WGG4�GGGGGG���'���P����@�P���N�S�������P%%�� �EF�H�������� �EFQH�� ��� � ����S�EFGH�6P%%��� ������$�%���$�������%�����YQZ����S�EFGH���������[ �G������� ������%P����[Z����[> \Q]^_���� � �� ������EFGH4P%%��>[4[>\Q]̂ _Z ���̀ \Q]̂ _V���6[����&��������A���&������������� �EFGH����������4G4P%%��� �������������4���� �����%�$�%���$�EFQH���������A���&

�&

������ ������������������������������������ ��������������4�GGGGG4WGGGGG������� �!"�#���

����� �����%P����!# ;�9 ��9- � ;����������% �9- �!"��9!�!,1*!�\Q�a������ ���%����$�%���%��&����� �!"�#�������$�%����

����� ������������AG�QAG�Q������������������� �� b�cd��Y`AG�W`AG�QAG�W`AG�Q�cc��� ��� U��%�� � ��� '(�!,(�5�7�! #84� 9 �< � �(�!/-2#�1!)!5-2

������ ���������������������������������� ���������4�GGGGG4WGGGGG��

������ ����������������������������������������4G4�G4����

����� ���������������������������������� ���������4�G��

Page 47: 001 Системный Администратор 10 2002

45№1, октябрь 2002

программирование

рекомендациям, на самом деле онвсе-таки может привести к проблеме.А именно, если общий объем читае-мого текста порядка 1 MB, то в про-цессе чтения в пике может израсхо-доваться не 1, а 2 мегабайта. Второймегабайт потом обычно освобождает-ся, но не гарантированно.

Эта тонкая проблема, по-видимо-му, связана с механикой переотведе-ния памяти в Perl. Оператор "$text.=$buf" время от времени увеличиваетпамять, занятую переменной $text. Впроцессе такого переотведения ин-терпретатору Perl, вероятно, требует-ся двойной объем памяти: под пре-жнюю строку $text и под новый, уве-личенный буфер для этой перемен-ной. В этот момент процесс и занима-ет лишний мегабайт. Видимо, еслипереотведение происходит в концецикла, второй мегабайт может и неосвободиться: в соответствии в общейидеологией Perl "запасать буферапамяти на будущее повторное исполь-зование".

Правильное решение описаннойзадачи - взять отведение памяти насебя. Например:

Если заранее неизвестно, чтопредстоит читать именно 1 MB, мож-но изредка (именно изредка!) аккурат-но выполнять самостоятельное пере-отведение памяти.

Для аккуратного отведения памя-ти можно предложить один из следу-ющих приемов:

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

Все вышеописанное протестирова-но и неплохо работает в ActivePerl 5.005

на NT 4.0 и в стандартном Perl изFreeBSD 4.2. Под ActivePerl 5.6 вWindows 2000 все оказалось несколь-ко хуже: undef не освобождает память.(По крайней мере, TaskManager не по-казывает сокращения памяти у процес-са Perl, пока длится 10-секундный sleep,следующий за вызовом undef.) Впро-чем, к моменту, когда вы будете читатьэту статью, возможно, этот недостатокуже будет исправлен фирмойActiveState.

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

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

��� ��������� ��GGGGGG�5-����� �������@���4�GGGGGG6�4_� �\Q��'2�,�(���!5���"�B1��-#(�5;.�)� ;�5C��D,�07�D�#-")�5

�220�� 1��� )!# -�(�,�����������GGGGGG��D �)���%P���� G��!# ;�9 ��9- � ;���> \Q]^_��������% �9- �!"��9!�!,1*!�\Q�a��� ��������4�4\Q]^_� � ��%�� '�"�7-8��������&��%���Z�GGGGGG������������4�� ����'�9-:�!"�1!10B1*D�+)�# �����&

efghi

Page 48: 001 Системный Администратор 10 2002

Поисковые и не только поисковыесистемы Интернет столь популярнысегодня, что люди проводят часы, об-суждая достоинства и недостатки тойили иной, алгоритмы и программы дляпоиска полнотекстовой информациина тех или иных носителях. И все этовремя не утихают горячие споры «про-фи» поиска и «ленивых пользовате-лей». Первые - сторонники чисто «ме-ханических» машин, поисковых сис-тем, которые вычисляют строгие ло-гические запросы и поддерживаютусечение слова справа «звёздочкой»;они убеждены, что лучше всяких ал-горитмов сформулируют, что же имнужно найти. Другие - наоборот, ста-раются отдать на откуп алгоритмампоисковика все магические преобра-зования исходного запроса и не за-думываться о том, что же там проис-ходит внутри.

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

Один достаточно иллюстративныйдиалог произошел на выставкеSofTool в 1995 году. Компания «Ага-ма», где я в тот момент работал, пред-ставляла одноименную систему поис-ка информации, размещенной на ло-кальных дисках компьютера. Надосказать, эта поисковая система ужетогда, несмотря на убогость DOS, подуправлением коего она работала, ужеделала полноценный словарный мор-фологический анализ обрабатывае-мых текстов и поисковых запросов, тоесть умела искать с учетом всех формрусских слов. И вот одна дама, про-тестировав систему и побеседовав оморфологической обработке текстовс господином Пархоменко, идеологоми руководителем проекта, воскликну-ла на весь зал: «Да ведь это никомуне нужно! Я сама прекрасно все най-ду, дайте мне только оператор усече-ния!». На беду, оператор усечения,как и весь традиционный набор логи-ческих операторов, в языке запросовприсутствовал. После получаса стуча-ния по клавишам дама со словами:«Вы меня не убедили!», - покинуластенд.

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

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

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

Программы, выполняющие стем-минг, или стеммеры, также существу-ют примерно столько же, сколько ипоисковые системы. И, надо отметить,в случае английского языка, (доста-точно простого и не склонного к из-лишней флективности, то есть измен-чивости слов), стеммеры успешносправляются с поставленной передними задачей. Так, классический«портеровский» алгоритм, хоть он игрешит сведением упоминавшейсяаббревиатуры DOS к формальнойоснове - глаголу do, тем не менее даетвполне корректное значение отноше-ния «сигнал/шум» в случае поиска ин-формации.

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

Сейчас уже никого не удивишь поисковой системой со встроеннымрусским, украинским или английским морфологическим анализатором,однако такой модуль достаточно дорог, и использование его в небольшихпродуктах не всегда коммерчески оправданно.

«СТЕММЕР»МОРФОЛОГИЧЕСКИЙ

АНАЛИЗДЛЯ НЕБОЛЬШИХ ПОИСКОВЫХ СИСТЕМ

программирование

46

Page 49: 001 Системный Администратор 10 2002

сильного шума, очень сложно, и по-строение такого набора правил срав-нимо по трудоемкости с построениемполноценного словарного морфологи-ческого анализатора, чем обычно изаканчиваются доведенные до логи-ческого завершения разработки вэтой области. Приведем простой при-мер - слово кровать. До сих пор всепрограммы стемминга для русскогоязыка успешно и совершенно логич-но признавали это слово изменяю-щимся по модели глагола, выделяяили формальную основу «кр» или влучше случае, «кров». Уважаемый чи-татель, мне кажется, по достоинствуоценит такой глагол - «я крую/кроваю,он кровает/круёт».

Однако за истекший год в этомнаправлении были сделаны серьез-ные шаги. Мартин Портер (MartinPorter) сделал доступными свои нара-ботки в области стемминга, наборыправил и инструменты для работы сними, для открытого сетевого сооб-щества, опубликовав проект наS o u r c e F o r g e ( h t t p : / /snowball.sourceforge.net/).Проектпредставляет собой специализиро-ванный язык обработки строк, пред-назначенный для изготовления алго-ритмов стемминга в информационномпоиске. Довольно быстро проект сталрасширяться, и сейчас доступны висходных текстах стеммеры для анг-лийского, французского, испанского,португальского, итальянского, немец-кого, датского, шведского и норвежс-кого языков. Русский поначалу остал-ся в стороне, однако недавно появи-лась поддержка и для него (http://snowbal l .sourceforge.net/russian/stemmer.html).

Тем не менее, по ряду причин,часть из которых обсуждалась выше,стеммер Snowball все равно далек отидеала. И основная причина заклю-чается в том, что он базируется наобобщенных правилах, составленныхлюдьми, в лучшем случае - лингвис-тами. А как известно, любое общееправило имеет исключения, приводя-щие в данном случае к неправильно-му выделению основы. Еще одно на-рекание - это «убежденность алгорит-ма в собственной непогрешимости»:алгоритм всегда дает один-един-ственный вариант формальной осно-вы слова, игнорируя все остальные по

внутренним соображениям. Именно всилу указанных недостатков и былопринято решение о разработке свое-го алгоритма и правил стемминга.

Отмечу сразу, что мыслей разра-батывать вручную правила усечениярусских слов не было даже изначаль-но, но было большое желание изго-товить алгоритм, который учитывалбы и сочетаемость букв в слове награнице возможного усечения, и час-тотность такой модели словоизмене-ния. Поэтому было принято решениестроить правила стемминга автомати-чески, обрабатывая большие масси-вы русских текстов. Задача сильно об-легчалась наличием русского морфо-логического анализатора, разрабо-танного еще в 1994 году во время ра-боты над проектом «Пропись 4.0».Анализатор этот работает и поныне впоисковых системах Апорт!( w w w . a p o r t . r u ) , Р а м б л е р(www.rambler.ru), <META> (www.meta-ukraine.com), хотя и пережил несколь-ко преобразований, в результате чегословарь уже придирчиво выверен, акод позволяет обрабатывать до 20 -30 тысяч слов в секунду. Подробнее сэтим анализатором и условиями егораспространения можно ознакомить-ся на странице автора (linguist.nm.ru).

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

ловии, что оно встретилось послефрагмента -ор-.

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

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

Результат - набор потенциальныхокончаний с условиями на предше-

программирование

47№1, октябрь 2002

Page 50: 001 Системный Администратор 10 2002

ствующие символы - был инвертиро-ван для удобства сканирования сло-воформ «справа налево» и представ-лен в виде таблицы переходов конеч-ного автомата. Подробнее устройствотаких таблиц описано в статье о сло-варном морфологическом анализато-ре, доступной по адресу http://linguist.nm.ru/ling/rus/help.htm. Мы желишь покажем на рисунке фрагменттакой таблицы, построенный для не-большого набора окончаний и усло-вий на предшествующие символы ос-новы. В качестве примера выберемуже упоминавшиеся формально пост-роенные правила: (-ар-)-ями, (-ор-)-ями, добавив к ним для наглядностиеще два - (-ск-)-и и (-сн-)-а, постро-енные, например, по словоформамдиски и весна.

Далее был разработан переноси-мый программный код на языке C,обеспечивающий сканирование пода-ваемых на вход форм слов на полу-ченных таблицах переходов. Особоследует отметить, что код этот не бе-рет на себя ответственность за выборконкретного способа усечения, нолишь строит все допустимые вариан-ты выделения формальной основы.Так, для словоформы начинающих-ся анализатор выделит формальныеосновы длиной 6, 8 и 10 символов, чтосоответствует глаголу начина-ть, при-частию начинающ-ий и возвратнойформе - начанающий-ся, то есть вы-делит псевдоморфемы, участвующиев образовании этого слова. Програм-ма-клиент, например поисковая ма-шина, вправе либо самостоятельнопринять решение о выборе того илииного варианта усечения, либо запом-нить все построенные варианты, чтообеспечит максимальную полноту по-иска. С другой стороны, для много-страдального слова кровать обучен-ный таким образом алгоритм выделитлишь одну формальную основу - ше-стибуквенную последовательностькроват-ь, что полностью соответству-ет истине. В ряде ситуаций анализа-тор принимает решение о невозмож-ности какого-либо усечения по даннойпоследовательности, как, например,в случае слова компьютер, что так-же полностью соответствует действи-тельности.

По ходу тестирования и отладкипостроенной технологии было введе-

но дополнительное правило, ограни-чивающее свободу алгоритма. Сутьправила состоит в том, что формаль-ная основа слова должна содержатьхотя бы одну гласную, иначе возмож-но построение весьма некорректныхоснов, как, например, усечение сло-ва спам до основы сп, что, как извес-тно, является распространенной абб-ревиатурой словосочетания «совме-стное предприятие». Интересно, чтобольшинство стеммеров, в том числеи используемый в поисковой системеЯndex (www.yandex.ru) для обработкинеизвестных слов, грешат в подобныхситуациях, в чем несложно убедить-ся, дав соответствующий запрос.

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

Особое внимание пришлось уде-лить поддержке различных кодовыхстраниц и возможной капитализации- начертанию слов в верхнем регист-ре. Действительно, при всей привле-кательности кодировки 1251 WindowsCyrillic и удобстве работы с ней, онане является ни единственной, ни дажесамой популярной. Преобразовыватьже строку из иных кодировок в жела-емую перед анализом весьма и весь-ма дорого по меркам «скорострель-ных» алгоритмов. Для обеспечениясовместимости анализатора с текста-ми в различных кодировках предус-мотрена возможность его настройкипередачей дополнительного парамет-ра - таблицы преобразования кодовсимволов из произвольной кодиров-ки в нижний регистр кодировки 1251

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

Хочется отметить, что весной 2002года в лаборатории общей и компью-терной лексикографии кафедры рус-ского языка Московского Государ-ственного университета было прове-дено сравнительное тестированиетрех программ русского стемминга:Snowball, описываемого алгоритма истеммера, разработанного там же подруководством докторов филологичес-ких наук А. А. Поликарпова и О. В.Кукушкиной. По результатам тестиро-вания описываемый стеммер показалнаиболее корректные в лингвистичес-ком отношении результаты при мак-симальной полноте и минимальномшуме, то есть количестве неверновыделенных основ.

Позже описанным способом былразработан также словарь стеммин-га украинского языка, который вмес-те с русским успешно применяетсядля анализа неизвестных слов в ук-раинской поисковой системе <META>(www.meta-ukraine.com), а также изго-товлена программа, позволяющаяавтоматически строить таблицы стем-минга для других языков из словарейISpell, доступных в сети Интернет.Однако следует оговориться, что впоследнем случае качество получае-мого словаря напрямую зависит откачества используемых материалов,которое чаще всего весьма низко.

Представленный продукт доступенв исходных текстах и может исполь-зоваться в свободной форме с усло-вием ссылки на источник. Архив мож-но загрузить по адресу http://linguist.nm.ru/stemka/stemka.tar.gz.

Зовут меня Андрей Коваленко, я работаю в на-стоящий момент в компании Рамблер, занимаюсьразвитием поисковой машины, до этого работал вМедиаЛингве, еще раньше в Агаме, где занималсяразработкой поисковой системы Апорт!.

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

программирование

48

Page 51: 001 Системный Администратор 10 2002

ОПРЕДЕЛЕНИЕГрафический лист из серии«Смыслограммы»

©1990Художник Игорь УСКОВ

www.igus.nm.ru

Page 52: 001 Системный Администратор 10 2002

JAVA:МАГИЯ ОТРАЖЕНИЙ

ЧАСТЬ I. ОСНОВЫ

ДАНИИЛ АЛИЕВСКИЙ

Page 53: 001 Системный Администратор 10 2002

51№1, октябрь 2002

программирование

Один из самых удивительных и ярких механизмов языкаJava — технология «отражения» (Java Reflection). К сожале-нию, в популярных учебниках нелегко найти подробную ин-формацию об этой интереснейшей области. А тем более —о подводных камнях и неожиданных возможностях, возни-кающих при программировании с использованием отраже-ний. Между тем, именно отражения позволяют Java с непод-ражаемым изяществом справляться с задачами, традици-онно непростыми в других языках — такими, как созданиеоболочки для компиляции Java-проектов (наподобие BorlandJavaBuilder или NetBeans), визуальное проектирование гра-фических компонентов (JavaBeans), сериализация объектови распределенные вычисления (RMI), и многие другие.

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

Мы начнем с простых вещей — простых для Java, но нестоль тривиальных в других языках. Пример такой «простойвещи» — динамическое расширение вашей программы но-выми классами от сторонних разработчиков, не требущеепереписывания и даже перекомпиляции вашей системы. Помере знакомства с отражениями, задачи будут усложнять-ся. В качестве завершающего примера, полностью исполь-зующего возможности отражений, я расскажу, как реализо-вать высокоэффективный интерпертатор выражения (фор-мулы), написанного на языке Java — эквивалент оператораeval() в скриптовых языках типа Perl или JavaScript.

Все написанное ниже относится к последней (на мо-мент написания статьи) версии Java: Sun Java SDK 1.4.

Где искать мир отражений?Отражения в Java — это два класса Class и

ClassLoader, расположенных в пакете java.lang, и специ-альный пакет java.lang.reflect, содержащий (в версии JavaSDK 1.4) 12 вспомогательных классов: Array, Member,Constructor, Field, Method, Modifier, InvocationHandler, Proxy,ReflectAccess, ReflectPermission, InvocationTargetException,UndeclaredThrowableExceptioCfn.

Проще всего осваивать технику отражений, начиная скласса Class. Более сложные вещи потребуют примененияклассов из пакета java.lang.reflect, прежде всего классов,описывающих: Constructor, Field и Method. «Высший пило-таж» работы с отражениями — это, пожалуй, создание гра-мотных наследников ClassLoader, позволяющих реализоватьсобственную систему загрузки классов.

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

В любом случае, статья не заменяет справочную до-кументацию фирмы Sun. Самую полную и свежую фир-менную документацию можно найти в Internet по адресу:http://java.sun.com/

Класс по имени ClassВ мире отражений все начинается с класса

«java.lang.Class». Для каждого Java-класса или интерфей-са, присутствующего в системе, существует экземпляр Class,содержащий подробную низкоуровневую информацию обэтом классе. Например, с помощью этого экземпляра мож-

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

Как получить экземпляр Class, соответствующий дан-ному классу (или интерфейсу) — например, классуjava.io.File? Для этого есть два основных способа.

A. Просто добавляем к имени класса суффикс «.class»,например:

(«clazz» — сознательно искаженное от «class»: компиля-тор не позволяет использовать в качестве идентификато-ра зарезервированное слово «class».)

B. Если мы располагаем экземпляром некоторого клас-са, может быть даже неизвестного в данной точке програм-мы, можно вызвать метод getClass(), присутствующий вкаждом Java-объекте (унаследованный от класса Object):

Здесь есть любопытный нюанс. Вообще-то, примитивныетипы Java — boolean, char, byte, short, int, long, float, double —обычно не считаются полноценными классами. Они не унас-ледованы от Object, для них не работает наследование и т.д.Тем не менее, с ними тоже ассоциированы экземпляры Class,которые можно получить способом A, например:

Существует даже специальный объект void.class — ониспользуется в довольно экзотических ситуациях при вы-зове методов через отражения. Экземпляры типа Classесть также у любого массива, например:

Что же можно сделать, располагая переменной типаClass для некоторого класса?

Прежде всего, можно получить полное имя класса (ска-жем, для отладочной печати) методом getName(). Например:String.class.getName() возвращает «java.lang.String».

Интересно посмотреть на имена классов для прими-тивных типов и для массивов:

Полностью алгоритм построения такого имени описанв документации на Java.

������ ������� ���� ������������

����������� �������� ������������������ ����������������� ���!"#$"%�&��'(")��%�������*���������� ������+����,����� ������-.��/.0��1�-������������ ��+�����

�����������������������

�����������������23������4#4����23�����,�����2563���������������������������

+� ������������7������ 8�98:$;$"�� <+� ��=+� ��23����������7������ 8�98:$;$"�� <2�=+� ��2323����������7������ 8�98:$;$"�� <22�=>�?���23����������7������ 8�98:$;$"�� 2@��������>�?����=

Page 54: 001 Системный Администратор 10 2002

52

программирование

Можно проверить, не является ли класс интерфейсом,массивом или примитивным типом: методы isInterface(),isArray() и isPrimitive(). Если класс — массив, можно полу-чить тип его элементов (т.е. соответствующий объектClass): метод getComponentType(). Для не-массивов этотметод вернет null.

Даже такие простейшие механизмы позволяют сделатьнечто полезное. Вот пример — функция для подсчетаобъема памяти, занятого массивом примитивных типов:

java.lang.reflect.Array — «странный»способ работать с массивамиПрежде чем переходить к более мощным (и ценным) воз-

можностям класса Class, давайте обратим внимание наjava.lang.reflect.Array. Этот очень простой класс из пакетаjava.lang.reflect представляет собой библиотеку статическихметодов, позволяющих выполнять все основные примитив-ные действия с массивом неизвестного (на этапе компиля-ции) типа, представленного общим типом данных Object.

Пример мы видели в приведенной выше функцииsizeOfArray() — метод getLength(). Этот метод объявлен висходном коде фирмы Sun следующим образом:

Любой массив в Java является объектом, т.е. наследни-ком Object, поэтому его можно передать в getLength() в ка-честве параметра. На самом деле, только массивы и можнопередавать в этот метод — как и в большинство других ме-тодов класса Array. Для объектов других типов методы классаArray возбуждают исключение IllegalArgumentException.

Большинство остальных методов класса Array предназ-начены для чтения и записи элементов в массив:

возвращает элемент номер index; если массив состоит изэлементов примитивного типа (byte, char и т.п.), возвра-щается объект-оболочка (Byte, Char, ...);

специальные версии get на случай, когда массив состоитиз элементов соответствующего примитивного типа;

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

двух методов:

Первый метод удобен для одномерных массивов, второй —позволяет создавать сразу многомерные массивы. В каче-стве componentType передается класс элементов — напри-мер, один из классов примитивных типов boolean.class,char.class и т.д.

Все подробности — в документации фирмы Sun.На первый взгляд у неискушенного Java-программис-

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

для массива v типа byte[], когда можно просто написать v[n]?Ответ — класс Array позволяет писать универсаль-

ные функции, принимающие на вход массив произволь-ного, неизвестного заранее типа. Пример такой функ-ции мы уже видели — sizeOfArray() из предыдущего пун-кта. Если бы не класс Array, нам бы либо пришлось на-писать 7 версий этой функции для каждого варианта мас-сивов примитивных типов, либо заменить вызовjava.lang.reflect.Array.getLength(v) чем-то вроде:

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

Я написал простую функцию toS(Object v, Stringseparator), преобразующую произвольный массив в стро-

/����������������������+A??���������������+����������?���?��B�� � ������ � �/ ����������� ���������������� �/ ����C�/�������+��� �/ ���������������������D? ,���,�E������A?������F1��/�� ��<7 ������??��=������������ �/ ���������������������G�HI����� �/ ������������D ?�������G�6I����� �/ ������������D�?������G�6I����� �/ ��������������������G�6I����� �/ �����������+� ��������G�JI����� �/ ������������ ��������G�JI����� �/ ������������ ����������G�0KI���� 0�����..�L"��':$'$�M8$"%��4N�� ����I�!#O�L"P��:$9%":�Q#"%"L�$����..�L"�&N"R4S4R4:�8$L�!�)T%"L�$R4"U�N��O9M)T�V�����+����� 0������D? ,���,�E������A?������F1��/�� ��<W�X� ,��� �/ �������/�=��� � ?���?�� ��������?�+�����A??������@����D��Y������..�%"��!����@����D���)#$&&$���������?�+�����A??���N�#T�$"�����..�L$�8Z�!"�%$&&48�N:�498�#(L�P���4N$�4�8�98:$;$"��"P��!#4LT��*

/��������������������������@����D��������??��������D? ,��E������A?������F1��/�� ��

/������������������������������??��[���������1�

/�������������� ��������\ ������������??��[���������1�[/��������������D�?�����D�?��������??��[���������1�

4� $L$#�P4�LM"� %"��!M� !#O� �4N�8� ����[� �D ?�[� ���[� � ��[+� ��[�� ����

/������������� ��������������??��[���������1[������������[/������������� ������\ ������������??��[���������1[�� ����

��[/������������� �������D�?��������??��[���������1[��D�?���4���!�

/������ ������� ������ ��,E�������������� � �/ ����C�/�[� ��������D�[

/���������������������,E��������������� �/ ����C�/�[����23������� ���

����\������

��������� +�����23G�������23��������DI������������ +��D ?�23G����D ?�23��������DI������������ +��D�?23G����D�?23��������DI������������ +����23G������23��������DI������������ +�� ��23G���� ��23��������DI������������ +�+� ��23G���+� ��23��������DI������������ +�� ����23G���� ����23��������DI� 0

Page 55: 001 Системный Администратор 10 2002

53№1, октябрь 2002

программирование

ку. Все элементы массива преобразуются (стандартнымобразом) в строки и конкатенируются через разделительseparator, заданный в качестве параметра функции. Воттекст этой функции:

Если аргумент v не является массивом, действие toSне отличается от стандартного метода v.toString(). Еслиv==null, возвращается пустая строка (обычно это удобнеестандартной реакции — возврата строки «null»).

Без класса Array пришлось бы написать 9 вариантовтакой функции — для 8 примитивных типов и для масси-ва объектов произвольного типа Object[].

Здесь нужно сделать одно важное замечание. Хотякласс Array действительно позволяет существенно эконо-мить текст программы и не писать разные варианты мето-да для массивов разных типов, следует иметь в виду —получаемый код сравнительно неэффективен. Скажем,цикл суммирования всех элементов числового массивачерез вызов java.lang.reflect.Array.getDouble() будет рабо-тать на порядок дольше банального:

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

Class.getResourceAsStream()- ресурсыОдин из самых очевидных примеров использования

класса Class — загрузка ресурсов.Ресурс в Java — это файл с данными, прилагаемый к

Вашей программе и обычно размещаемый «рядом» сclass-файлами. В графических приложениях и апплетахэто чаще всего изображения (jpg- или gif-файлы), но стаким же успехом это может быть и файл специальногоформата — например, содержащий справочные таблицыили какие-либо ваши объекты.

Наиболее общий способ прочитать файл-ресурс произ-вольного формата, расположенный «рядом» с некоторымклассом — обратиться к методу getResourceAsStream()объекта Class, соответствующего данному классу. В ка-честве параметра этому методу нужно передать путь к фай-лу ресурса относительно каталога, в котором размещен вашкласс. В качестве результата getResourceAsStream() вернетобъект InputStream, с помощью которого можно прочитатьфайл ресурса стандартными средствами ввода/вывода Java.

Для наиболее популярных типов ресурсов, таких как

изображения, обычно существуют более удобные спосо-бы прочитать ресурс — например, метод getImage() клас-са java.applet.Applet. Но для текстовых файлов и файловнестандартного формата getResourceAsStream(), как пра-вило, — самое разумное решение.

Вот пример законченного класса, использующего этутехнику:

В этом примере файл «mydata.txt» должен быть рас-положен в том же каталоге, что и class-файл«MyClassWithResource.class».

Файл ресурса необязательно размещать в том же ката-логе, что и class-файл. Если он расположен в одном из под-каталогов этого каталога, в качестве имени ресурса нужнопередать относительный путь, разделяя имена подкатало-гов символом «/» (как это принято в Internet и Unix). Можнотакже указать в качестве имени ресурса «абсолютный»путь, начинающийся с символа «/». Тогда Java будет ис-кать ресурс во всех каталогах, перечисленных в путях по-иска классов CLASSPATH — т.е. по тем же правилам, покоторым отыскиваются class-файлы программы.

Может возникнуть вопрос — зачем нужен специаль-ный метод класса Class, когда можно прочитать файл ре-сурса обычными средствами файлового ввода/вывода?

Основная причина — использование методаgetResourceAsStream() является гораздо более общим ре-шением, работающим в большем числе ситуаций.

Например, по традиции, законченные наборы классов —Java-приложения или библиотеки — принято упаковывать вархивы JAR и устанавливать на компьютер именно в такомвиде. Классы Java прекрасно загружаются непосредствен-но из архива JAR, без предварительной распаковки. То жесамое относится и к ресурсам, загружаемым методомgetResourceAsStream() — или более специальными метода-ми типа java.applet.Applet.getImage(). В то же время, обыч-ные средства файлового ввода/вывода для чтения ресурсаиз JAR уже непригодны — нужно использовать специаль-ные классы для анализа и чтения JAR-файлов.

/�������������>�?����� >�������[�>�?������/�?�� ?������+����������?���?��<=����+����������������A??����������������������+���������������?�+�����A??������@����D�����B��?���?��<=�����>�?���\�++�?�?���������,�>�?���\�++�?��������+ ?������X�B��X]�����X^^����������+��X_B��?�������//������/�?�� ?��������?�������//����>�?���������+�����������������?�+�����A??�������[X��������*����?���?��?������� >�?��������*��?���?��>�?���������+���*

� ��������B�B�+ ?������X�B��X]������D��X^^���^��2X3�

��/ ?�� ���� �Y�/������������`������a��Db�� �?������/�������������+�����>�?������C�1�b�� �?��7�����<��������1�=���/�������������+�����>�?������C�1�b�� �?�����������������>�?�������<=������?���������E�/��>�?������?�����`������a��Db�� �?��������������������b�� �?��A�>�?������C�1�b�� �?��7������������+����?���������������D? ,���,�����7 �� ���F1��/�� ����C�1�b�� �?��7���^=�� �

+ ���=��������>�?���\�++�?�������,�>�?���\�++�?���?���������������������E�/��>�?���b����?�?����?����,�E�/��>�?���b����?���?������������D�?23���+����,��D�?25HcKJ3���������������������,D����������?����?�?������+[B[��+������D��_�B���������������//������+[B[�����������*������������� >�?����������*�����D��E�F1��/�� ��������������/?���>���XC?����������*������C�1�b�� �?��������*��/������������� ��������>�?���23��?���������>������ ���/?������<@ �����?�� �?��I=������>������ ���/?��������C�1�b�� �?������**

Page 56: 001 Системный Администратор 10 2002

54

программирование

Аналогичная ситуация — апплеты, когда файлы ресур-сов и class-файлы находятся на сервере. МетодgetResourceAsStream() в этом случае обеспечит чтение ре-сурса с сервера через Internet.

Тем не менее, в некоторых случаях для чтения ресур-са все-таки может быть целесообразным использованиетрадиционных средств файлового ввода/вывода — конеч-но, если вы не используете JAR и пишете сервлет или при-ложение, а не апплет. Например, для достижения макси-мальной производительности может понадобиться отобра-зить ресурс в память средствами отображения файлов изпакета java.nio, появившегося в Java начиная с версии SDK1.4. Или, может быть, вы захотите просканировать ката-лог с ресурсами и загрузить все файлы с определеннымрасширением — для сканирования каталога в классе Classнет соответствующих средств.

Если ресурс, как это принято, расположен рядом сclass-файлами — или, скажем, если вы хотите поработатьс самими class-файлами вашего приложения — то при-дется решить следующую задачу: определить дисковыйкаталог, в котором находится ваш class-файл. Будьте вни-мательны: это отнюдь не простая задача.

Ниже приведен текст функции, возвращающей полныйпуть к class-файлу.

Прежде всего мы получаем имя класса без имени па-кета, добавляем к нему расширение «.class» и передаемметоду getResource() объекта Class. Этот метод возвра-щает экземпляр класса java.net.URL, представляющийфайл в виде универсального пути к ресурсу (URL, UniversalResource Locator). В нашем случае (когда классы распо-ложены в обычных файлах в локальной файловой систе-ме) URL будет выглядеть примерно так:

Метод getFile() объекта URL «отрежет» префикс «file://», оставив все остальное без изменений.

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

Первое отличие: в URL подкаталоги всегда разделя-ются прямым слэшем /, в то время как в операционныхсистемах, отличных от Unix, могут использоваться другиесимволы (например, обратный слэш \ в случае Windows).Это различие несущественно для Java — классы пакетаjava.io прекрасно будут работать и с именем файла, запи-санным через прямые слэши.

Но есть и второе отличие. Если путь к файлу содержит

пробелы, русские буквы или другие символы, недопусти-мые в стандарте URL, то они будут закодированы комби-нациями вида %XX, где XX — ASCII-код символа. Такое имяфайла непригодно для обработки средствами ввода/выво-да Java. Для восстановления «нормального» имени файланужно вызвать метод java.net.URLDecoder.decode(), обяза-тельно указав при этом кодировку символов (encoding).

Опытным путем я установил, что для кодирования не-латинских букв в имени файла Java использует кодиров-ку UTF-8 — по крайней мере, на Windows-платформе. Ксожалению, я не нашел в документации прямых указа-ний, что это всегда будет так на всех платформах. Поэто-му я бы порекомендовал, по возможности, все же разме-щать свои классы в каталогах, путь к которым состоиттолько из латинских символов — тогда приведенная вышефункция будет достаточно надежна.

Class.forName() и Class.newInstance() —динамическая загрузка классовМы подошли к рассмотрению по-настоящему важных и

интересных технологий мира отражений. Речь пойдет о фун-даметальном и чрезвычайно мощном механизме Java: ди-намической загрузке произвольного класса по заданномуимени. Эта возможность встроена непосредственно в Javaи реализуется классом Class. В других языках типа С++ илиDelphi аналогичных целей можно достигнуть, используя спе-циальные средства конкретной операционной системы (типазагрузки dll в Windows функцией loadLibrary()), но в Java этосделано по-настоящему удобно.

Итак, Вашему вниманию предлагается статический ме-тод Class.forName(). Вот его формальное объявление:

Метод отыскивает в системе (среди путей поиска клас-сов CLASSPATH) класс с заданным именем className ивозвращает соответствующий экземпляр класса Class.Имя className должно быть полным, т.е. включать имяпакета. Например:

Если такой класс отсутствует, возбуждается исключе-ние ClassNotFoundException.

После получения переменной типа Class, следующеенаиболее типичное действие — создание экземпляратолько что загруженного класса. Для этого служит методClass.newInstance(). Его объявление:

В нашем примере вызов newInstance() мог бы выгля-деть так:

Чтобы этот метод мог выполниться, у загруженного клас-

/����������������� ���������������������������������..�CD��+����,�����1���� �����+������������������ +���[..�� ����/�?�� +�VAb� ?�a���?�� �?����>�?����������������7������������������?����������E���1�+�<�=�^0��� � ��� ���������b�� �?����^=������=���������������?�����������������Wb@d�� ��?���� ����[=WC� J-����*�����D����� �W���// ?���F�� ����F1��/�� ��������*��?���?����,����� ���������*

+���I..NT�(e)e!4&)�8�%Te)$�$#�PT.4%Oe)#$&&$������

/�������������������+ ?7����>�?���������7�����D? ,�� �����7 �� ���F1��/�� �

������ ������� ������+ ?7����<��������>�?���=��

/��������������,E����������D? ,�� E���������� �F1��/�� �[� E������A�����F1��/�� �

������ ������ ��������,E����������

Page 57: 001 Системный Администратор 10 2002

55№1, октябрь 2002

программирование

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

Конечно, этого еще мало, чтобы работать с полученнымобъектом. Если вы не знаете, что умеет делать класс — ка-кие у него есть методы, что они ожидают получить на входеи для чего они предназначены — вы не сможете извлечь изнего ничего полезного. Для формального определения, что«умеет» класс, в Java существует стандартный механизм —интерфейсы. Остается просто применить этот механизм.

Например, предположим, ваша программа должна внекоторые моменты выполнять перевод с одного языкана другой. Формально это можно описать интерфейсом:

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

Описанная техника может оказаться очень полезнойпрактически в любой достаточно большой и серьезной си-стеме, рассчитанной на разработку многими участника-ми. Многие компоненты таких систем являются достаточ-но изолированными, и их набор может быть совершеннонеизвестен на этапе компиляции основной программы —известны лишь интерфейсы, который они обязуются реа-лизовывать. Например, так обычно строятся системыplugin’ов — модулей, добавляемых к уже работающей си-стеме. В подобных случаях механизм отражений — мето-ды Class.forName() и Class.newInstance() — становитсяединственным грамотным решением.

Constructor, Field, Method — работа склассами через отраженияНа самом деле технология отражений позволяет сделать

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

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

Перечисленные методы возвращают массивы объек-тов типа Constructor, Field и Method. Эти классы содер-жатся в пакете java.lang.reflect и обеспечивают исчерпы-вающий доступ к полям, конструкторам и методам.

Сразу бросается в глаза наличие двух версий методов:getXXX и getDeclaredXXX (где XXX — «Constructors»,«Fields» или «Methods»). Поначалу это может даже несколь-ко сбить с толку — какой версией следует пользоваться?

getDeclaredXXX возвращает список членов класса (кон-структоров, полей или методов), объявленных при описа-нии класса, но не унаследованных от классов-предков. Приэтом в список включаются все члены, независимо от ихуровня защиты — т.е. public, protected, private и друже-ственные члены.

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

При желании, конечно, можно получить и максимальнополную информацию — список всех членов, объявленныхв самом классе либо в любом из его предков. Для этогодостаточно организовать цикл по цепочке классов-пред-ков, пользуясь специальным методом Class.getSuperclass().

Кроме получения полного списка, можно также отыс-кать в классе конкретный член. Для этого служат методы:

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

Аргумент name в этих методах должен содержать имятребуемого члена. Аргумент parameterTypes связан с воз-можностью Java перегружать конструкторы и методы —определять несколько конструкторов, либо несколько ме-тодов с одинаковым именем, отличающихся только типа-ми параметров. (В случае конструкторов это единствен-ный способ создать много конструкторов класса.) В каче-стве parameterTypes нужно отдать массив объектов типаClass, соответствующих типам всех параметров конструк-тора или метода.

Разница между вариантами getXXX и getDeclaredXXXздесь та же самая, что и в случае методов получениясписков.

Здесь я бы порекомендовал написать небольшой тест,

/����������?+����@�������C?������ ?����/������>�?�����?��������>�?����� �?��[����>�?����� �?��@�������[����>�?������?���@�����������..�N":"8�!4���")&��� �?���&�O9M)$�� �?��@���������..�L$�O9M)���?���@���������*

>�?����� �?����<�")&�[��:"'Tf;4U�N":"8�!$=�>�?���� � �?��@��������� <b������=�>�?���� ��?���@��������� <F�����D=��������������������+ ?7����<N�#L�"e4%Oe)#$&&$eN":"8�!�4)$=�������� ������ ��������,E�����������+��g� ������������� +�@�������C?������ ?��������D? ,���,�F1��/�� ��<���=�����..�&��';$"%��'��h4')"I�T)$9$LLMU�)#$&&���..�L"�:"$#49T"���:"'T"%MU�4L�":S"U&[���..���"��L"�O8#O"�&O�N":"8�!�4)�%*>�?���� ?������� ��@�������C?������ ?� ������ � ��?��������� �?��[� �?��@�������[��?���@���������

/������ � ���?��� ?23� ���� ���?��� ?���[/�����������23������������������[/������`��D �23���������`��D ����[/������ � ���?��� ?23� ���d����?��� ���?��� ?���[/�����������23����������d����?����������[/������`��D �23���������d����?��`��D ����

/������� ���?��� ?������� ���?��� ?������23�/�?�����?C�/���[/����������� �����������>�?���������[/������ `��D �� � � ���`��D ��>�?���� ����[� �����23

/�?�����?C�/���[/������ � ���?��� ?� ���d����?��� ���?��� ?������23

/�?�����?C�/���[/���������������������d����?��������>�?���������[/������ `��D �� � � � � ���d����?��`��D ��>�?���� ����[� �����23

/�?�����?C�/���

Page 58: 001 Системный Администратор 10 2002

56

программирование

который распечатает списки всех конструкторов, полей иметодов (объявленных и унаследованных) какого-нибудькласса. Для преобразования объектов Constructor, Field,Method в строки можно использовать стандартный методtoString(). Попробуйте распечатать такие списки для клас-сов без конструкторов, с пустым конструктором, с конст-руктором, обладающим параметрами, с private- и public-полями. Попробуйте унаследовать класс и переопреде-лить в нем (под тем же именем) public-, protected- илиprivate-поле. Такой текст хорошо помогает понять, как вJava устроены классы, конструкторы и наследование.

Как реально работать с классами Constructor, Field,Method?

Прежде всего, заметим, что все они реализуют общийинтерфейс Member, позволяющий:� получить символьное имя члена (конструктора, поля

или метода) с помощью метода:

� получить обратную ссылку на класс, в котором объяв-лен данный член (т.е. тот класс, который возвращаетэтот член в соответствующем массивеgetDeclaredXXX()), с помощью метода:

� получить набор битовых флагов — модификаторовданного члена с помощью метода:

Модификаторы — это битовые флаги, описывающие,обладает ли данный член следующими свойствами: public,private, protected, static, final, synchronized, volatile, transient,native, abstract или strictfp. Полный список модификато-ров и средства работы с ними можно найти в классejava.lang.reflect.Modifier — см. документацию фирмы Sun.

Кстати заметим, что некоторые модификаторы (напри-мер, public) определены также у классов; их можно получитьметодом Class.getModifiers(). Для классов определен ещеодин модификатор — java.lang.reflect.Modifier.INTERFACE,означающий, что объект Class ассоциирован не с классом,а с интерфейсом.

Главное назначение классов Constructor, Field, Method —конечно, получить доступ к соответствующим членам, т.е. вслучае конструкторов — создать экземпляр класса, в слу-чае полей — прочитать или изменить поле, в случае мето-дов — вызвать метод.

Это делается достаточно просто. Чтобы не дублиро-вать документацию по Java, я просто приведу пример го-тового тестового класса, где использованы все основныеприемы доступа к членам:

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

Для передачи параметров в конструкторы и методыиспользуется массив объектов (типа Object[]). Если нуж-но передать параметр примитивного типа, он «заворачи-вается» в соответствующий класс-оболочку — в случаеint это объект Integer. Такое «заворачивание» — традици-онная практика в мире отражений.

Для доступа к полю в классе Field реализованы общиеметоды get() и set(), рассчитанные на произвольный объект,и частные версии getBoolean(), getInt(), ..., setBoolean(),setInt(), ..., рассчитанные на примитивный тип поля. Пер-вым параметром у этих методов всегда передается экзем-пляр объекта, к полю которого нужно получить доступ.

Для вызова метода служит метод invoke() классаMethod. Ему передается экземпляр объекта, метод ко-торого следует вызвать, и список параметров в виде мас-сива Object[].

Если метод класса возвращает результат (а не опи-сан как void, как в данном примере), этот результат бу-дет возвращен в качестве результата invoke — в видеобщего типа Object. (Примитивный тип в этом случае,как обычно, «заворачивается» в класс-оболочку.)

Располагая объектом Constructor или Method, можно уз-нать список типов всех параметров в виде массива Class[]:для этого служат методы Constructor.getParameterTypes()и Method.getParameterTypes(). В случае метода можно так-же узнать тип результата: Method.getReturnType(). Кстати,это та самая экзотическая ситуация, когда находит приме-нение исключительно редкий объект void.class (я упоми-нал об этой объекте в разделе 2): void.class будет возвра-щен getReturnType(), если метод объявлен как void.

С помощью классов Field и Method можно также по-лучить доступ к статическим полям и методам класса,даже не создавая экземпляра объекта. При этом в ка-честве первого параметра методов getXXX(), setXXX()или invoke() допускается передать null. Можно, скажем,легко написать Java-код, аналогичный по действиюстандартной утилите «java» — а именно, запускающийстатическую функцию «public static void main(String[]args)» у произвольного класса. Техника интерфейсов,описанная в предыдущем разделе, не позволила бы этосделать.

/������>�?�������7������

/������ ������ ���d����?�����������

/�������������` ��+��?����

��/ ?�� ��������?�+�����Y�/������������C������������/��������������/������C�������������������D��������*��/������ ��������������������0�*��/������ ���������/0���������/0�*��/������>�?����� >�?�������?���?���^--�*

��/������������� ��������>�?���23��?�����D? ,��F1��/�� ��������������������C���������������� � � � � ���?��� ?� ��� ���������� ���?��� ?���,� �����23

����������*������������ ������,E����������,������23����,�E�����?�H5�*������������+�����������������-�-������>������ ���/?������+����E��� �������+����E��� [H6������>������ ���/?������ ������`��D ��������������`��D ��-�-[��,������23��*���������� X�� [��,������23��*������>������ ���/?������ ������������������`��D ��-�-[��,������23�����������*���������� X�� [��,������23����,�E�����?�H�*������>������ ���/?������ ����**

Page 59: 001 Системный Администратор 10 2002

57№1, октябрь 2002

программирование

Обход защиты JavaВ очень многих учебниках по Java подчеркивается, что

модификаторы protected и private вместе с «дружествен-ным» уровнем доступа (отсутствие модификаторов) по-зволяют обеспечить «100-процентную защиту» ваших по-лей и методов от использования посторонними класса-ми. Например, вы никогда не сможете добраться до поля

объявленного в исходном коде класса String и представ-ляющего реальное содержимое строки.

На самом деле все это не так. Смотрите, как можнодобраться до этого самого поля и «нелегально» изменитьстроку — вопреки известному утверждению, что тип Stringявляется абсолютно неизменяемым:

Здесь «магический» метод — setAccessible(). Этот ме-тод (и симметричный getAccessible()) имеется у всех клас-сов Constructor, Field, Method и предназначен специальнодля того, чтобы отключить стандартную проверку моди-фикаторов, осуществляемую Java-машиной.

(Естественно, все это сработает только при условии,что в вашей версии Sun Java SDK реализация класса Stringточно так же основана на private-поле «char value[]». Таккак это поле скрытое, фирма Sun вправе в любой моментпереименовать его или вообще заменить чем-нибудь дру-гим.) Спрашивается — зачем же это сделано? И развеэто не является брешью в системе безопасности?

Что до второго вопроса — разумеется, методsetAccessible() контролируется менеджером безопаснос-ти Java (так же как, например, работа с файлами), и ни-какая мало-мальски защищенная Java-система не позво-лит злоупотребить подобной возможностью.

А чтобы понять, зачем это нужно, взгляните на любуюсреду разработки Java-проектов — скажем, NetBeans илиJavaBuilder. Традиционная возможность подобных сред —показать все поля и методы некоторого класса, напри-мер, визуальной компоненты — в том числе и скрытые, ав некоторых случаях — дать возможность отредактиро-вать значения полей. Язык Java уникален в том отноше-нии, что подобные действия можно легко выполнить со-вершенно законными средствами самого языка, не при-бегая, скажем, к анализу исходного текста программы.

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

Приведем два примера. Во-первых, в Java поддержива-ется механизм сериализации. Достаточно реализовать ввашем классе пустой интерфейс-индикаторjava.io.Serializable, и появляется возможность полностью (т.е.со всеми полями и вложенными объектами) записать этотобъект в поток java.io.ObjectOutputStream и впоследствиипрочитать из потока java.io.ObjectInputStream.

Те, кто изучал механизм сериализации Java, согласят-ся — во многом этот механизм напоминает черную магию.Каким-то образом классы java.io.ObjectInputStream иjava.io.ObjectOutputStream, без всяких дополнительных под-сказок со стороны разработчика класса, «догадываются»,как записать или прочитать все поля объекта, включаяprivate-поля. Более того, для «подсказки», когда она всеже требуется, используются private-методы writeObject() иreadObject() — классы java.io.ObjectOutputStream иjava.io.ObjectInputStream каким-то образом обнаруживаюти вызывают эти методы.

Конечно же, в действительности эта «черная магия» —не что иное, как магия отражений. Описанные выше техно-логии, в том числе метод setAccessible(), в принципе, позво-ляют даже разработать свою собственную схему сериали-зации, отличную отстандартной, предлагаемой фирмой Sun.

Второй пример — технология RMI. Это чрезвычайномощный механизм, позволяющий распределять вычисле-ния по сети — так, чтобы с точки зрения кода Java вызовметода выглядел, как обычно, а на самом деле этот ме-тод отрабатывался на другом компьютере. Здесь тоже необойтись без технологий отражения. Только они позволя-ют динамически превратить объект (со всеми своими по-лями) в поток данных, передать его по сети, реконструи-ровать объект на другом компьютере и вызвать нужныйметод — и все это скрыто от пользователя класса.

Конечно, все это не повод, чтобы использовать отра-жения не по назначению для «взлома» защиты Java. От-ражения следует использовать только тогда, когда без это-го нельзя обойтись — иначе вы потеряете все преимуще-ства, которые дает идеология объектно-ориентированно-го программирования.

ЗаключениеЯ постарался описать самые, на мой взгляд, важные и

интересные аспекты технологии отражений. Статья — несправочник и не учебник. Многие вещи «остались за бор-том». Не все методы классов были описаны; некоторые спе-цифичные классы, такие как java.lang.reflect.Proxy, я вооб-ще не рассматривал. Чтобы получить полную и точную ин-формацию, всегда лучше обращаться к первоисточнику —документации фирмы Sun. Кроме сайта http://java.sun.com,документацию почти всегда можно найти в комплекте по-ставки Java или извлечь из комментариев к исходным тек-стам фирмы Sun.

Я также хотел бы порекомендовать книгу: «Язык Про-граммирования Java», К.Арнолд, Дж.Гослинг, Д.Холмс, Из-дательский дом «Вильямс», Москва — С.-Петербург —Киев, 2001. Это наиболее грамотная из попадавшихся мнекниг на русском языке. Она написана сотрудниками фир-мы Sun, участвовавшими в разработке технологии Java —т.е. в некотором роде является первоисточником.

��/ ?�� ��������?�+�����Y�/������������i��X>�?�������/������������� ��������>�?���23��?�����D? ,��F1��/�� �������>�?�������<i��� g=�����>������ ���/?�������������������+������������������d����?��������<����=��������..�j%"LL�����d����?�������[�$�L"���������I������..�N�&#"!L4U�%"��!�N:�&���L"�L$h"#�'M�&):M��P��N�#O����+����A�����������?���������D�?23���������D�?23�+����������������2k3��lGm�����>������ ���/?�����������**

/?������D�?�����23�

Page 60: 001 Системный Администратор 10 2002

программирование

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

Сколько раз вам приходилось слышать или самим за-давать вопросы типа “как я могу сохранить информациюиз HTML-форм на своих Web-страницах?” или “как мне сде-лать счетчик посещений?” или, наконец, “как мне защититькод своих Web-страниц от всеобщего обозрения?” В самомязыке HTML нет никаких простых способов обработки дан-ных HTML-форм. Броузер может лишь собрать информа-цию из форм и передать ее на Web-сервер. Обработка ин-формации может быть возложена на CGI серверные рас-ширения. Одно название чего стоит! А ведь их еще нужнонаписать и отладить своими руками, потратив немало вре-мени на изучение различных стандартов и протоколов! Бе-зусловно, это полезное, с точки зрения общего развития,занятие. Кто из нас не проходил на первых курсах институ-та сопромат или теорию машин и механизмов, с тем, что-бы позже получить диплом программиста или специалистапо микропроцессорам?! Так ли уж это было необходимо?

Пара слов пояснений для тех, кто не совсем в курсе.Хотя бы для того, чтобы понять от чего Вас может уберечьColdFusion.

CGI, или Common Gateway Interface, - это стандартныйшлюзовый интерфейс. Проще говоря – это некоторый стан-дарт или набор правил, определяющий порядок общения

(взаимодействия, обмена данными, если угодно) междуWeb-сервером и прикладными программами, выполняющи-ми ту или иную задачу. По существу, написанные вами CGIпрограммы расширяют возможности Web-сервера, допол-няя его нужной вам функциональностью. Отсюда, собствен-но и второе название CGI программ – серверные расшире-ния. В принципе, CGI программа может быть написана налюбом языке: C/C++, Perl, TCL, Visual Basic, Clipper, Fortran.Все зависит от того, какая у вас система и в какой средепрограммирования вы чувствуете себя более комфортно.Главное, чтобы ваша программа обеспечивала средстваобщения с Web-сервером, или, говоря иначе, удовлетворя-ла стандарту CGI. Естественно, если вы пишите на С, топеред запуском вам нужно скомпилировать программу.Если же вы используете один из языков-сценариев типаPerl, TCL или Unix shell, то все, что вам надо сделать передзапуском, это поместить файлы в каталог /cgi-bin, где поумолчанию их будет искать Web-сервер. В чем же недоста-ток CGI программ? Во-первых, не каждый специалист поэлектронной торговле или Web-дизайнер знает С или VisualBasic. Во-вторых, CGI программы слишком расточительныпо отношению к системным ресурсам. При каждом обра-щении на вашу страницу и, соответственно, при каждомзапуске CGI программы, система порождает новый поток,выделяя для него в оперативной памяти компьютера но-вое пространство. И если у вашего сайта много посетите-лей (а ведь именно для этого вы и создаете сайт), то легкоможет сложиться ситуация, когда в памяти сервера одно-

COLDFUSIONИЛИ,возможно, лучшее решение для созданиядинамических сайтов

Я намеренно вынес спорное утверждение взаголовок, главным образом с целью привлечь

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

Александр Меженков

Page 61: 001 Системный Администратор 10 2002

программирование

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

Однако вернемся к теме статьи...Вначале немного истории. В далеком (по меркам Сети)

1995 году два брата Дж.Дж. И Джереми Эллейр (J.J. ИJeremy Allaire) в США (ну а где же еще?) основали новуюкомпанию «Allaire Corporation» для продвижения первого вмире сервера Web-приложений, который они назвалиColdFusion. Одной из причин создания ColdFusion как рази была сложность создания сайтов, управляемых даннымис помощью CGI программ. Перед одним из братьев – Дже-реми – стояла задача периодического обновления элект-ронной версии издававшегося в печатном виде журнала.Занятие это было крайне утомительным, и Джереми обра-тился к своему брату-программисту с просьбой написатьдля него какое-нибудь приложение, которое избавило быего от излишней траты времени и сил, и позволило бы емусосредоточиться на основной задаче – собственно, обнов-лению электронной версии журнала. Когда проект был за-вершен, оба брата осознали, что они испекли горячий пи-рожок, который наверняка многим придется по вкусу. Не-долго думая, братья основали новую компанию и, не мудр-ствуя лукаво, дали ей свою фамилию. Вложив в свое дети-ще 18 тысяч долларов личных сбережений, шестью года-ми позже, в 2001 году, братья Эллейр продали его корпо-рации Macromedia более чем за 360 миллионов долларов.У вас еще осталось желание писать низкоуровневые про-цедуры ввода/вывода?

Что же представляет собой этот чудесный продукт, ко-торый принес своим создателям такую прибыль? Безус-ловно, вам знакомы термины hardware и software. Так вот,ColdFusion – это middleware. Термином middleware называ-ют программное обеспечение, осуществляющее некоторыепреобразования. В самом общем смысле сервер приложе-ний ColdFusion является посредником, преобразующим вашкод, написанный на языке высокого уровня, называемомCFML (ColdFusion Markup Language) в теги HTML-докумен-та, который может отобразить Web-броузер. Официальное

название ColdFusion – сервер Web-приложений, но в зави-симости от того, как вы решите его использовать, он мо-жет быть средством разработки Web-страниц, сервером базданных или вашим счастливым билетом в благополучнуюжизнь. От версии к версии ColdFusion предлагал все боль-ше возможностей. Версия 1.5 в 1996 году содержала всеголишь 35 тегов, обеспечивавших простейшие функции дос-тупа к базам данных и поддержки электронной почты. Се-годня 5-я версия ColdFusion предоставляет более 80 тегови 255 функций для решения практически любой задачи,которая может возникнуть в Web-программировании.

ColdFusion позволяет начать создание нового приложе-ния на основе прочного фундамента развитого и полнос-тью ориентированного на Web-среду языка программиро-вания, обеспеченного серьезной поддержкой солидной ком-пании (Macromedia), ее бизнес - партнерами и тысячамиразработчиков, публикующих свои решения на специаль-ном Web-ресурсе под названием Developers exchange. Этотресурс настолько богат, что прежде, чем приступать к раз-работке решения какой–бы то ни было задачи, имеет смыслзаглянуть сюда. Очень часто здесь можно найти совершен-но бесплатно готовое решение.

Конечно, на рынке существует много других техноло-гий, которые вы можете использовать для создания дина-мических Web-приложений. Диапазон их достаточно ши-рок: от “open source” технологий, таких как Perl и PHP, докоммерческих Java Server Pages (JSP) или Microsoft ActiveServer Pages (ASP). При таком богатстве выбора, что насможет побудить использовать ColdFusion, который, кстатисказать, является коммерческим и весьма недешевым про-дуктом. Его цена больше $1,000. Но пусть вас это не сму-щает. Во-первых, его покупают, как правило, не частныелица, а фирмы. А во-вторых, практика показывает, что сто-имость конечного продукта или, говоря другими словами,“стоимость владения” (Total Cost of Ownership), включаю-щая, помимо цены инструментальных средств, стоимостьразработки алгоритмов, кодирования и отладки, часто ока-зывается ниже, чем стоимость приложения, разработанно-го с помощью “бесплатных” средств. Деньги, вложенные вColdFusion окупаются очень быстро.

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

Page 62: 001 Системный Администратор 10 2002

60

программирование

ся технологий, вам не нужно быть гуру программированиядля того, чтобы начать работу с ColdFusion и успешно за-вершить свой первый проект, который приятно удивит ва-шего шефа. Эта простота использования отнюдь не озна-чает отсутствия мощи и функциональной гибкости. Простоблагодаря усилиям программистов из Allaire, а теперь иMacromedia, многие сложные вещи происходят за сценой.ColdFusion упрощает решение большинства задач, такихкак обработка данных форм или выполнение запросов базданных. Однако когда у вас возникает нужда выполненияболее сложных операций, ColdFusion предоставляет вамтакие возможности. В компаниях, использующихColdFusion, сложные задачи, сборку всего приложения иего отладку осуществляет, как правило, действительноклассный высокооплачиваемый специалист, тогда как про-стые операции возлагаются на новичков, которые еще толь-ко учатся программированию.

Другим важным достоинством ColdFusion является на-личие версий для всех популярных систем и Web-серве-ров. Неважно, на чем вы работаете: Windows 95/98/NT/2000,Solaris, Linux или HP-UX. ColdFuison совместим с большин-ством известных Web-серверов: Netscape Enterprise иiPlanet, Microsoft IIS и PWS, O’Reilly Website, Apache. Выможете переносить ColdFusion приложения с платформына платформу и легко переключаться между различнымисистемами управления базами данных.

Наиболее близким конкурентом ColdFusion являетсятехнология ASP. Какими, качествами кроме межплатфор-менной совместимости, может еще похвастать ColdFusion?Легкость и простота. Языком ASP является VBScript – под-множество Visual Basic, который сложнее ColdFusion. Срав-ним, например, два фрагмента кода. Вначале на ASP(VBScript):

Теперь то же самое на ColdFusion:

Что проще – решать вам.При использовании ASP одной распространенной про-

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

Но покажите мне программиста, который пишет безошибок. Подобная забывчивость приводит к тому, что про-странство памяти, занимаемое объектом базы данных, неосвобождается. Страницы с таким кодом, обращение к ко-торым происходит несколько раз в минуту, весьма интен-сивно расходуют оперативную память, что очень скороможет привести к зависанию сервера. ColdFusion отсле-живает подобные ситуации автоматически. В части функ-циональных возможностей (без привлечения продуктов сто-ронних фирм) ColdFusion также дает некоторую фору ASP.

Вот лишь несколько из них: работа с почтой, встроенныеHTTP, POP и FTP клиенты, встроенный поисковый меха-низм. Это ни в коем случае не агитация в пользу ColdFusion,просто объективная попытка познакомить с малоизвест-ным в России пакетом.

Технология ASP, в свою очередь, также имеет преиму-щества. Но это уже тема другой статьи.

За названием ColdFusion на самом деле скрываются двапонятия: собственно сервер Web-приложений ColdFusion иязык программирования ColdFusion, называемый CFML(ColdFusion Markup Language). Файлы приложенияColdFusion имеют расширение .cfm и называются шабло-нами (templates). Шаблоны ColdFusion наряду с тегами ифункциями CFML могут содержать обычные HTML-теги ивстроенные JavaScript и/или VBScript сценарии. CFML частьшаблона обрабатывается сервером приложений, в резуль-тате чего динамически генерируется часть выходной стра-ницы основанная на данных формы, базы данных и такдалее, которая позже объединяется со статической егочастью, представленной HTML-тегами и сценариямиJavaScript/VBScript в единый выходной HTML-документ, пе-редаваемый Web-серверу.

Рассмотрим, как ColdFusion обрабатывает пользова-тельские запросы.

1. Web-броузер направляет запрос к Web-серверу стребованием открыть файл ColdFusion. Эти файлы имеютрасширение .cfm.

2. Получив запрос, Web-сервер перенаправляет егосерверу приложений ColdFusion.

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

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

5. Web-сервер отправляет полученную от сервераColdFusion страницу на пославшую запрос клиентскую ма-шину.

В заключение приведем полезные ссылки, а также при-меры сайтов, построенных с использованием ColdFusion.

�� �������� ������������� ����� ������������� ����������������������

�� ���� ��� �� ������������ �� ����� � �� ������������ !� ��������"������� �����������#� ��

��$%&'&()*+(,-./(+&'(01&-(+&,-.(+2(/.(3456���7��888�8����9�345�

��:0;<=>+.('&,&1/&=>/?3451/0@/(==6���7��6��6�������������� ���9��

�� A/0@/(==+?> 1/02<;.? B������ �� C +?+>D+>@0 E)(2>)*'(3�F �������$.-G2(H>=0H+0-;(I(.*1/0J+?>�����F�E>/-&&6���7��888�������� �����������8����

���K�F����L��M�6��9��N0))>;'&,@0.0E?O/>D>+&P+(3�F ������6���7�� �K�M�������� ������� �K�F�����9�FF��Q��� �M����

!�3�F ������%0/<=?6���7��8�R�������������� ���������F �������

S�T�CF���20;<=>+.('&,103�F ������6���7��888�������� �����������������F ������� �������������6��F

Page 63: 001 Системный Администратор 10 2002

программирование

Page 64: 001 Системный Администратор 10 2002

62

программирование

Недавно я занимался разработкой утилитки, позволяющей запускать с сервера по сети некоторыепрограммы на определённое время. При этом обмен происходил через UDP-сокеты. Для написанияклиентской части необходимы были требования, чтобы она работала под управлением Windows2000, и обычный непривилегированный пользователь не мог выключить или включить её.

ПРОГРАММИРОВАНИЕСЕРВИСОВВ WINDOWS 2000

ВСЕВОЛОД СТАХОВ

Page 65: 001 Системный Администратор 10 2002

63№1, октябрь 2002

программирование

Для этой цели идеально подходят сервисы — слу-жебные программы, выполняющиеся в фоновом режи-ме и без возможности завершения процесса через дис-петчер задач. Для управления сервисами используетсяадминистративный компонент Windows NT —services.msc (находится в папке «Администрирование»панели управления). Как сервисы организовано множе-ство системных служб Windows, таких как сетевые кли-енты и серверы, утилиты управления оборудованием(пресловутый Plug and Play), а также драйверы ядра.Из компонента управления сервисами можно изменятьрежим работы сервисов. Сервис характеризуется со-стоянием: запущен, остановлен, приостановлен. Дляуправления сервисами используются соответствующиекнопки: запустить, остановить, приостановить (доступ-но лишь для некоторых сервисов), перезапустить. Мож-но сделать, чтобы некоторые сервисы запускались призапуске компьютера. Для этого существует три режи-ма запуска сервиса: автоматический (auto) — сервисзапускается при входе в систему вручную, (manual) —сервис запускается по требованию пользователя илисистемы, отключено (disabled) — сервис вообще не бу-дет запускаться.

Для изменения режима запуска откройте диалогсвойств сервиса и на вкладке «Общие» выберите нуж-ный режим. На данной вкладке также показано имя иописание сервиса (их можно изменить), а также путь кисполняемому файлу сервиса. Кроме того, можно из-менять и другие параметры сервиса. Для этого смотри-те встроенную справку Windows. При любых манипуля-циях с сервисами учтите, что изменение базы данныхсервисов доступно только администраторам. Кроме это-го, возможна модификация сервисов на членах NT до-мена через MMC (Microsoft Management Console —mmc.exe) пользователем, имеющим права администра-тора домена.

Создание сервиса в ОС Windows — задача нетриви-альная. Например, создание демона в ОС Unix намно-го проще, хотя, я думаю, система сервисов лучше про-думана и более централизована. Для создания новогосервиса, прежде всего, его нужно зарегистрировать вбазе данных сервисов. Для этого открывается база дан-ных сервисов функцией OpenSCManager для записи-со-здания, далее добавляется сам сервис функциейCreateService. После этого система может запуститьприложение, зарегистрировавшее себя сервисом, но за-пуск идёт несколько необычным образом: запускаетсяне WinMain, а ServiceMain, которая определяет обра-ботчики событий сервиса (таких как запуск, пауза, ос-тановка) функцией RegisterServiceCtrlHandler, устанав-ливает текущее состояние сервиса SetServiceStatus ивыполняет функцию StartService для каждого зарегист-рированного сервиса (их может быть несколько). Не-много сложновато, не так ли? Но реально создать сер-вис ещё сложнее, так как данные функции принимаюточень много параметров, например функцияCreateProcess принимает аж 13 (!) параметров. Но я всёже попытаюсь вкратце рассказать о каждой функции иприведу конкретный пример сервиса. Итак, начнём с

функции открытия базы данных сервисов:

Функция возвращает дескриптор базы данных серви-сов с именем DatabaseName, если данный параметр ра-вен NULL, то используется база данных по умолчанию (дляэтой же цели можно использовать константуSERVICES_ACTIVE_DATABASE) на компьютереMachineName или на локальном компьютере, если дан-ный параметр NULL. Параметр DesiredAccess определя-ет режим доступа к файлу. Обычно используются констан-ты GENERIC_READ, для чтения GENERIC_WRITE для со-здания новых сервисов или изменения параметров ста-рых и GENERIC_EXECUTE разрешение на выполнениесервисов. При ошибке возвращается NULL, иначе — дес-криптор базы данных.

Далее происходит регистрация сервиса функциейCreateService, которая возвращает дескриптор сервисадля использования в данном процессе:

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

SC_HANDLE hSCManager — дескриптор базы дан-ных сервисов, полученный функцией OpenSCManager.

LPCTSTR lpServiceName — строка (до 256 символов),реальное имя сервиса в базе данных.

LPCTSTR lpDisplayName — данный параметр — имясервиса, которое показывается в инструменте управ-ления сервисами.

DWORD dwDesiredAccess — флаг доступа к серви-су. Может принимать любые значения доступа.

Обычно используются константы GENERIC_READ,GENERIC_WRITE, GENERIC_EXECUTE, а также значе-ние SERVICE_ALL_ACCESS для предоставления полно-го доступа к сервису.

DWORD dwServiceType — флаг типа сервиса, то естьто, как он будет выполняться системой.

Возможные значения:SERVICE_WIN32_OWN_PROCESS — сервис суще-

ствует в виде отдельного процесса;SERVICE_WIN32_SHARE_PROCESS — сервис раз-

деляет процесс под названием services с другими сер-висами;

SERVICE_WIN32_KERNEL_DRIVER — сервис явля-

�������� ��� ����������

������������ � ��������������������� ����������������� �� ���� !��"#������"�������� !��"#������������� !��"#�� �������� !��"#��$��$���$�����������%�� ��� ��� �������������$ "!�"��&�$'����� !����"#� �("���������������"������������������������� ��� ������������� ��#$�"

)*

��������!������ � �����$����� �+� ������ ����$����� �+� � , ��� ���� !��������"������)*

Page 66: 001 Системный Администратор 10 2002

64

программирование

ется драйвером ядра (то есть сам является частьюядра);

SERVICE_WIN32_FILE_SYSTEM_DRIVER — сервис пред-ставляет собой драйвер файловой системы. Практическивсе сервисы, не являющиеся системными, создаются каксобственные процессы SERVICE_WIN32_OWN_PROCESS.

В этом случае, если необходимо, чтобы сервис взаи-модействовал с рабочим столом, можно указать черезбитовое “или” флаг SERVICE_INTERACTIVE_PROCESS.

DWORD dwStartType — флаг способа запуска сер-виса, может принимать следующие значения:

SERVICE_BOOT_START — служба запускается заг-рузчиком, NT то есть при загрузке ядра (допустимо толь-ко при создании драйвера ядра);

SERVICE_SYSTEM_START — сервис запускаетсяпосле загрузки ядра при инициализации драйверов (этотакже допустимо только для драйверов);

SERVICE_AUTO_START — служба запускается привходе в систему;

SERVICE_DEMAND_START — сервис запускаетсядругим приложением (в том числе инструментом управ-ления службами);

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

DWORD dwErrorControl — флаг поведения при ошибке.Для большинства сервисов (кроме критичных и системныхдрайверов) разумно писать SERVICE_ERROR_IGNORE дляигнорирования ошибки или SERVICE_ERROR_NORMALдля вывода сообщения о невозможности запуска (такжедобавляется запись в системный журнал). Для драйверовпри невозможности их загрузки обычно происходит откатсистемы и (или) перезагрузка.

LPCTSTR lpBinaryPathName — полный путь к испол-няемому файлу сервиса. Учтите, что если путь содер-жит пробелы или является очень длинным, то писатьего нужно в кавычках внутри строки, то есть “\”d:\\myfolder\\my_super service.exe\».

LPCTSTR lpLoadOrderGroup — имя группы сервиса,обычное значение — NULL, для указания, что сервисне принадлежит никакой группе.

LPDWORD lpdwTagId — этот параметр содержит теггруппы, которые применяются драйверами для иденти-фикации внутри группы, обычное значение — NULL.

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

LPCTSTR lpServiceStartName — имя пользователядля запуска сервиса. Имя вводится в формате Имя_до-мена\имя_пользователя (или .\имя_пользователя длялокального домена). Если данный параметр NULL, тоиспользуется системный профиль LocalSystem, что под-ходит для большинства сервисов.

LPCTSTR lpPassword — параметр, определяющий парольдля выбранного профиля. Если параметр равен NULL, то счи-

тается, что пароль — пустая строка. Для профиля локаль-ной системы LocalSystem пароль всегда должен быть NULL.

Итак, если вы дочитали, до этого момента, то всёостальное должно показаться Вам детскими играми.

Кстати, сообщу информацию, которая многим пока-жется полезной: после регистрации сервиса его пара-метры записываются в системный реестр Windows в улейHKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\имя_сервиса. Для людей, любящих копаться в настрой-ках ОС сообщаю: большинство системных драйверовявляются сервисами и их настройки можно поменять вреестре. Например, очень интересным является ключTcpip — можно менять очень много “скрытых” настроексети (включая настройки сетевых карт!). Для поклон-ников безопасной сети есть ещё один ключик:Lanmanserver — позволяет прикрыть некоторые дырыбезопасности, например NetBios NULL session. Но вер-нёмся к реальности — к созданию сервисов. Чтобы ещебольше отпугнуть читателя, приведу пример созданияфункции CreateService:

После создания сервиса считайте, что ваше дело за-вершено – смело пишите CloseServiceHandle(SC_HANDLE sh) и выходите из программы. Тут я сде-лаю небольшое лирическое отступление. Как извест-но, в ОС Windows после загрузки программы в памятьвызывается специализированная функция main для кон-сольных приложений и WinMain для приложений GUIWindows.

Программа, работающая как служба, ведёт себя не-сколько по-другому: вызов сервиса происходит функ-цией StartService(SC_HANDLE sh, DWORD param_count,char **parameters), после чего он загружается в память(если ещё не был загружен) и вызывается функцияServiceMain(DWORD param_count, char **parameters), ко-торая также ведёт себя очень хитро, но об этом чутьпозднее.

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

��� ��������� ����� � �������������� ��� ������� �� ���"#������"������� "#������������ "#�� ���$���$����%�� ��� ��� ������$ "!�"��&�$'����"#� �("��������"������������������ ��� ��� ��� ��#$�")*

-����'"� .#��"$#�/�0

���� ������ ������ �++ ���)1

����������*����������",*223456789:;7<=>?547@85;@

��A(����%�����B���� ���� ,��CDE11F���������G������������ ��H�1�I����I��HH*

�J� ���.K)122L=9M56<4>=7NMO4P:;@22L=9M56547@85=

�J�Q�� ����������������� ���������� ���� ,��))1

Page 67: 001 Системный Администратор 10 2002

65№1, октябрь 2002

программирование

В принципе, всё не так уж и сложно, хотя я кое-чегоне рассказал. Во-первых, функция OpenService служитдля загрузки сервиса в память. Функция принимает трипараметра: дескриптор базы сервисов, имя сервиса и типдоступа – тут всё понятно. Для удаления сервиса исполь-зуется функция DeleteService(SC_HANDLE sh), котораявозвращает ноль в случае ошибки. При использованииданной функции учтите, что при открытии сервиса фун-кцией OpenService, вы должны указать в правах досту-па единственный флаг DELETE для удаления его из базы.Для запуска самого сервиса используется функцияStartServiceCtrlDispatcher(LPSERVICE_TABLE_ENTRYlpServiceStartTable). Функция принимает единственныйаргумент — массив строк, содержащий две строки — имясервиса и имя функции-обработчика, заканчивается спи-сок двумя пустыми строками. После этого начинаетсяобработка функции сервиса ServiceMain.

Итак, начало самого интересного — написание фун-кции ServiceMain. Данная функция служит для запуска,инициализации и изменения статуса сервиса. Поведе-ние данной функции строго регламентировано: во-пер-вых, она должна заполнить поля структурыSERVICE_STATUS значениями параметров данного сер-виса; во-вторых — зарегистрировать обработчик собы-тий сервиса функцией RegisterServiceCtrlHandler; и, в-третьих — выполнить действия по инициализации сер-виса и установить состояние сервиса функциейSetServiceStatus. Итак, обо всём по порядку. Думаю, от-дельного описания заслуживает структураSERVICE_STATUS:

Итак, обычно вначале устанавливается значение ста-туса SERVICE_START_PENDING, затем устанавливает-ся обработчик сообщений, инициализация сервиса итолько после этого статус сервиса устанавливается вSERVICE_RUNNING. При данных действиях не забудьтекорректно установить dwWaitHint, иначе система сочтёт,что ваш сервис не успел запуститься, и замочит его безсожаления. Для регистрации обработчика событий ис-пользуется функция SERVICE_STATUS_HANDLERegisterServiceCtrlHandler(LPCTSTR service_name,LPHANDLER_FUNCTION handler_function) — первый па-раметр — имя сервиса, второй — указатель на функ-цию-обработчик, данная функция возвращает дескрип-тор состояния сервиса для функции SetServiceStatus илиNULL в случае ошибки. Для установки текущего состоя-ния сервиса используется функция SetServiceStatus(SERVICE_STATUS_HANDLE ssh, LPSERVICE_STATUSstatus) — первый параметр — дескриптор состояния, авторой — указатель на структуру статуса. После этогоприведу простенький пример главной функции:

#������$��$��F� �R� �S��'�� �������G)*H

H�J� ���EEK)122T474U=P;U8P9=7=O4:7

�J�������� ���CVD� WX�Y))���� �����������)*22Z5:=P;@6=547@85=45[8=7X

NMO4P:X��J�������� ���CVD� WX'Y))

'����� �����������)*22ZU=[4P84547@85=45[8=7XNMO4P:X'

H����1

#������$��$��W% " '� ��Y)*���'��XV*

H���'��\*

H

���'����A(������I�1� !�� "#�����������* ] ^:; 9;[4 ;>P=_=4: :; `4� _:; 8 @

aMP6b88��� ����������:/4/:89978[;`4P8c547@85=�;:U4[dP?e�U7=e@47cU7=�U7=e@47fg)/

� !�� "#�'������� ��* ] = @;: ^:; 594b8a8_456;4 9;[4 X5;U47`8: :46Mh44 5;5:;cP84 547@85=� 8O4PP; 4N; U;[`P= M5:=XP=@[8@=:d �������� ��/

3;9M5:8O?4 >P=_4P8ci��A(����!���X547@85;5:=P;@[4P*��A(�����������(�& X 547@85 >=9M56=4:5c*��A(����!�����(�& X 547@85 ;5:=P=@[8@=4:5c*��A(���I��(�&X547@85M`4>=9Mh4P*��A(���!��(�I����(�&X547@8597;U;[`=4:7=<;:M*��A(����I�����(�&X547@859474j;U8:@74`8O9=M>?*��A(����I��X547@85P=j;U8:5c@74`8O49=M>?/

� !��"#�$���$���������"*]<8:;@=cO=56=�5;U47`=h=cU;9MX5:8O?45;5:;cP8c547@85=�_474>9;<8:P;4F8[8G)/

3;9M5:8O?4 6;P5:=P:?i

��A(����������!�X547@85O;`4:<?:d;5:=P;@[4P*

��A(����������I���!��(�IX547@85O;`4:<?:d9;5:=@[4P85Pc:59=M>?*

��A(����������I��! �X547@85<MU4:;9;@4hkP978@?j;U48>585:4O?/

� !�� "# ��lKS���$"�* ] ^:;: 9=7=O4:7 5;;<h=4: 585:4O4>P=_4P84�6;:;7;4@;>@7=h=4:547@85978;m8<64�9;U7;<P44;m8<6=;974U4[c4:5c 5[4UMnh8O 9=7=O4:7;O/

� !��"#������������J��S���$"�*]6;P674:P=c;m8<6=�97;X8>;m4Um=c@547@854/

� !�� "#����o�$���* ] = ^:; 9;[;`4P84 97;N7455X<=7= 978>=9M564X;5:=P;@64547@85=�859;[d>M4:5cU[c@8>M=[8>=b8897;Xb455=>=9M56=547@85=/

� !�� "# ������* ] @74Oc @ O8[[8546MPU=j� 6;:;7;4 `Uk:@?>?@=nh=c97;N7=OO=U;8>O4P4P8c[8<;:46Mh4N;5:=:M5=�[8<;"#����o�$���/p5[8^:;N;P45[M_8[;5d�:;5_8:=4:5c�_:;>=X9M56547@85=<?[P4MU=_4P/p5[8U=PP;4>P=_4P84P;[d�:;M<8X4P8cP497;85j;U8:/

H*

�$�"����������� ���� !�� ����������+ ���)1� !���� �'�*� !�������J����$�*

��A(������I� ����������� �'�* 22q:= := 5=O=c5:7M6:M7= 5:=:M5=

22r@;:O?4k>=9;[Pc4O ����������� �'�/"#����������� E

��A(�� (�lK�! ����!���* ����������� �'�/"#�'������� �� E

��A(�����������(�&* ����������� �'�/"#�$���$���������" E

��A(����������!�*����������� �'�/"# ��lKS���$"�E\*����������� �'�/"#������������J��S���$"�E\*����������� �'�/"#����o�$���E\*����������� �'�/"# ������Es\\\*22t4N85:787M4O;<7=<;:_865;<?:8e ����������� �'�� �"�� E

�������������������� �"����F���������G�

�������������� �"���)*

�J������������ �'�� �"��EE���A(������I�������)\)

Page 68: 001 Системный Администратор 10 2002

66

программирование

Прекрасная функция, не так ли? Ну и для последне-го штриха расскажу ещё про обработчик сообщений.Если Вы когда-нибудь писали GUI программу, то, на-верное, знаете, что обработчики событий — это длин-ная функция, которая получает номер события и выпол-няет в соответствии с этим некие действия. Так, в сер-висах наблюдается нечто подобное. Формат функциидолжен быть такой:

void WINAPI Handler(DWORD fdwControl); параметрfdwControl содержит текущее сообщение от системы.

Возможные значения этого параметра:SERVICE_CONTROL_STOP — cервис должен оста-

новиться.StartServiceCtrlDispatcher (LPSERVICE_TABLE_ENTRY

lpServiceStartTable) SERVICE_CONTROL_PAUSE —cервис должен перейти в режим паузы.

SERVICE_CONTROL_CONTINUE — cервис долженвыйти из режима паузы.

SERVICE_CONTROL_INTERROGATE — cервис дол-жен сообщить о себе информацию.

SERVICE_CONTROL_SHUTDOWN — cистема соби-рается выключаться.

Ну вот, в принципе, и всё. Для дальнейшей инфор-мации Вы можете обратиться к MSDN. Но для большин-ства сервисов этой информации оказывается достаточ-но. Итак, дерзайте!

1#������$��$��F� ��$���������� �"���J'����$�G)*

���'��*H

22r:4947d@?9;[Pc4OP46;:;7?48P8b8=[8>=b8;PP?4U4eX5:@8c/

�� �'� E ���������(���� ��u ��$�� ���� ����v�����J����$�)*

22T7;@47c4O�6=697;m[=8P8b8=[8>=b8c�J��� �'�QE�!���!�)

122wm8<6=X;5:=P=@[8@=4O547@858@?j;U8O

����������� �'�/"#�'������� �� E��A(����!���*

����������� �'�/"#����o�$���E\*����������� �'�/"# ������Es\\\*����������� �'�/"# ��lKS���$"�E�� �'�* ����������� �'�/"#������������J��S���$"� E

�����J����$�*

������������ �'� ������������ �'�� �"���v����������� �'�)*

���'��*H

22x5k97;m[;M594mP;i)8UkOU=[dm4/����������� �'�/"#�'������� ��E��A(���I��(�&*����������� �'�/"#����o�$���E\*����������� �'�/"# ������E\* �J �Q������������ �'� ������������ �'�� �"���

v����������� �'�))

1�� �'�E&��� ����$��)*#������$��$��F� ��$������������� �'�yX�F)*

H

22g47@85P=_=[7=<;:=:d/

#������$��$��FB� ������#$�o�QG�\)*

���'��*H

Page 69: 001 Системный Администратор 10 2002

СЕТИ

Page 70: 001 Системный Администратор 10 2002

68

сети

АНАЛИЗАТОРСЕТЕВОГОТРАФИКА

ВведениеЕсли Вы - системный администратор,

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

Обзор технологииEthernetДля начала вспомним, как функциони-

рует сеть Ethernet (те из вас, кто уже знакомс данным вопросом, могут пропустить этотпараграф). IP-пакеты (дейтаграммы), источ-ником которых является приложениепользователя, инкапсулируются в Ethernet-кадры (пакеты Ethernet-протокола, переда-ваемые в сети). Каждый кадр содержит ис-ходный IP-пакет и другую информацию, не-обходимую для доставки его адресату, вчастности, 6-ти байтовый Ethernet-адрес(MAC-адрес) назначения, который при по-мощи протокола ARP ставится в соответ-ствие IP-адресу назначения. Таким образом,сформированный кадр, содержащий пакет,начинает свое путешествие от хоста-отпра-вителя к хосту-получателю через кабельноесоединение.

На уровне протокола Ethernet маршру-тизация отсутствует. Другими словами, кадр,отправленный хостом-отправителем, непопадает напрямую хосту-получателю, а бу-дет доступен для всех хостов, объединен-ных в сеть. Каждая сетевая карта принима-ет кадр и считывает из него первые 6 байт.Эти байты содержат MAC-адрес хоста-по-лучателя, но только одна карта в сети опре-делит его как свой собственный и передасткадр для дальнейшей обработки сетевомудрайверу. Сетевой драйвер проверит поле«Тип протокола» заголовка кадра и, осно-вываясь на этом значении, направит инкап-сулированный пакет соответствующей при-емной функции данного протокола. В боль-шинстве случаев это протокол IP. Прием-ная функция изымает IP заголовок из при-нятой дейтаграммы и передает инкапсули-рованное сообщение соответствующемумодулю протокола транспортного уровня(например, TCP или UDP). Эти протоколы,в свою очередь, обрабатывают свои заго-ловки и передают данные протоколам при-кладного уровня. В течение этой «экскур-сии» по различным уровням сетевого стекаисходный пакет теряет все служебные поляпротоколов и, в конце концов, данные, пе-редаваемые в пакете, принимаются пользо-вательским приложением.

Пакетные сокетыПри создании сокета стандартным вы-

зовом socket (int domain, int type, int protocol)параметр domain определяет коммуникаци-онный домен, в котором будет использовать-

ся сокет. Обычно используются значенияPF_UNIX для соединений, ограниченныхлокальной машиной, и PF_INET для соеди-нений, базирующихся на протоколе IPv4.Аргумент type определяет тип создаваемо-го сокета и имеет несколько значений. Зна-чение SOCK_STREAM указывается при со-здании сокета для работы в режиме вирту-альных соединений (протокол TCP), а зна-чение SOCK_DGRAM - для работы в режи-ме пересылки дейтаграмм (протокол UDP).Последний параметр protocol определяетиспользуемый протокол (в соответствии сIEEE 802.3).

В версиях LINUX, начиная с 2.2, появил-ся новый тип сокетов - пакетные сокеты.Пакетные сокеты используются для отправ-ления и приема пакетов на уровне драйве-ров устройств. Сокеты данного типа созда-ются вызовом socket (SOCK_PACKET, inttype, int protocol). Параметр type равен илиSOCK_RAW, или SOCK_DGRAM.

Пакеты типа SOCK_RAW передаютсядрайверу устройства и принимаются от негобез всяких изменений данных пакета.

SOCK_DGRAM работает на более вы-соком уровне. Физический заголовок (MAC-адрес) удаляется перед тем, как пакет от-правляется на обработку пользователю.

Пример реализацииИтак, приступим непосредственно к со-

зданию анализатора. Для этого нам необ-ходимо:

- определить необходимые переменные;- получить параметры сетевого интер-

Page 71: 001 Системный Администратор 10 2002

69№1, октябрь 2002

сети

фейса (IP-адрес, маску подсети, номер под-сети, размер MTU, индекс (номер) интер-фейса);

- создать пакетный сокет и привязатьего к определенному интерфейсу;

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

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

ПеременныеНеобходимые заголовочные файлы:

Структура для хранения принятого IP -пакета:

Функция полученияпараметров сетевогоинтерфейса

int fd; - дескриптор сокета.Создадим сокет:

Скопируем имя интерфейса в полеifr_name структуры ifr:

Получим IP адрес интерфейса:

Получим маску подсети:

Получим номер подсети:

Получим размер MTU:

Получим индекс (номер) интерфейса:

Переведем интерфейс в неразборчи-вый режим. Для этого получим значение

Cтруктура для хранения параметровсетевого интерфейса:

Структура для получения адресной ин-формации:

Структура для хранения заголовка IP-пакета:

Структура для хранения заголовкаEthernet-кадра:

Вспомогательная структура, содержа-щая параметры интерфейса:

��������������� ������������ �������������

��������

��������������������������������������������������������������������������������������������������������������������������������������������������������������������������

������������ ����

�������������������

������������ ����

�����������������

������������� ���� �������� ��������� ���!����������������������

������

int e0_r, - дескриптор сокета;rec; - размер принятого пакета в байтах;char *buff; - буфер для приема пакетов.

Переменные разместим в файле ip.h.

���""���#��������"$%&'()*�+,-./01$2*344��3�4�

�������"�5������6�4��������"�7�8�4�

���������5����6�������������������������� ��������� �"�����������������*���������*������������������4

�������� "���7�������*� 59�6*����4�

���"������"��*�+&,-0&%$//1*����4��3�4� �������"5�����64��������"784�

�������":�*� 3*� ��;���� "���������������44�������":�*�:���7�������*���;����"�������������44�������":���7��*� :��������������*��;����"���� 44�

���7����!��� #� �������!���"���7����*���7���4�

���"������"��*�+&,-0&%2)<*����4��3�4� �������"5�����64��������"784�

�����7������#�����7���������

���"�������"��*�+&,-0&%&'/(=*����4��3�4

�������"5�����64��������"784�

�����7��������#�����7�������������

���"������"��*�+&,-0&%'()2$+.*����4��3�4

�������"5�����64��������"784�

�������":�*� 3*� ��;���� "���������������44�������":�*� :���7����������*� ��;���"��������������44�������":���7���*� :��������������*��;����"���� 44�

Page 72: 001 Системный Администратор 10 2002

70

сети

флагов интерфейса:

Установим флаг неразборчивого ре-жима:

Установим новое значение флагов ин-терфейса:

Параметрами функции getifconfig явля-ются структура struct ifreq *ifr, имя интер-фейса char *intf и структура struct ifparam*ifp. Номер подсети определяется при по-мощи вызова функции check_subnet, при-веденной ниже.

Установкой флага интерфейсаIFF_PROMISC мы добиваемся приема всехпакетов, даже если они не адресованынашему хосту.

Функция определенияномера подсети

Функция check_subnet сканирует пер-вый переданный параметр (маску подсе-ти) до первого появления 1 и запоминаетэту позицию. Эта позиция соответствуетчислу разрядов, отведенных в адресе насетевую составляющую. Далее, во второмпереданном параметре (адресе) происхо-дит логический сдвиг на число разрядов,отведенных под адрес хоста. Таким обра-зом, у нас остается только сетевая состав-ляющая, которая и является адресом под-сети.

Функция для созданияпакетного сокетаЗаголовочные файлы:

Структура для хранения адресной ин-формации об интерфейсе (см. файл <linux/if_packet.h>):

Создадим пакетный сокет:

Выделим память для структуры structsockaddr_ll s_ll:

Заполним поля структуры s_ll необхо-димыми значениями:

Привяжем сокет к интерфейсу:

Возвратим дескриптор сокета в вызы-вающую функцию:

Функция getsock_recv принимает в ка-честве параметра индекс интерфейса ивозвращает дескриптор пакетного сокета.Значение поля protocol в системном вызо-ве socket равно htons (ETH_P_ALL). Этоозначает, что мы будем принимать пакетывсех протоколов. Все входящие пакетыбудут передаваться пакетному сокету дотого, как они будут переданы протоколам,реализованным в ядре. Список возможныхпротоколов приведен в файле <linux/if_ether.h>.

Для получения пакетов только с опре-деленного интерфейса используется фун-кция bind: таким образом мы соединяемпакетный сокет с интерфейсом, адрес ко-торого указан в структуре struct sockaddr_ll.Если этого не сделать, мы будем получатьпакеты со всех сетевых интерфейсов, ко-торые в данный момент активны.

Главная функция

Получим параметры сетевого интер-фейса:

Выделим память:

Получим дескриптор пакетного сокета:

Цикл приема пакетов:

����7������� ��>#�&%%?1,2&+-�

���"�������"��*�+&,-+&%%@$0+*����4�3�4�

�������"5�����64�������"��4��������"784�

��������8�

������������������������������������������������������������������������������������������������������������������������ ���������A�"���������4

��� ���

���������������� ����

���""���#��������"+,-.?$-.()*�+,-.1$B*������"()C?$@@4�44��3�4�

�������"�5������6�4��������"�7�8�4�

�������":���*�3*���;����"���������������44�

�������������#�?%?$-.()�7�DEF�GHIJDK����������������#�������"()C?$@@4�7�DEF�FLEMENKJNHOH�FLHDHIHPK���������������#�������7�MHNJL�EMDJLQJRGK���������������#�?$-.()C,+)�7�DEF�FKIJDK�"SPT�PHIKPUMHR�NKVEMW4

��� ""!���� "��*� "������� ��������4�:���*���;����"����������������44�3�4�

�������"5!���64�������"��4��������"784�

���������5����6��������"4

�������":���*�3*���;����"������������44����" ��������� �":���*�5���36*�:���4

�3�4� �������"5 ��������� 64������"84�

!����#�"�����4�������"��������X�8Y4�������":��*� 3*� ��;���� "������

�������44������������ #� "���� �4� ������ "��������7���;����"������������44�

��#"��������������4:���������

���""�3��#� ���������A�"���������44��34�

�������"5 ���������A64�����"84�

����"��4�

Z[M\PEN�[\QJL]!;����"!���*��������X8Y4�����#�3�

Принять пакет:���#���A����� "�3�*� "���

�4!���*��������X8Y*�3*�'<@@*�'<@@4����"����34�

�������"5���A����64�����"84�

�������"��4��

���"�������"��*�+&,-0&%%@$0+*����4�3�4�

�������"5�����64�������"��4��������"784�

^&)+�_`0@,^$@��������!���

+(-)&,'�������������!���]

������!� 7� GHaLKMENKSLJG�bHcbLKDK�Ec�Q\MIdEE

��A��!�*������A����*�e�!�XYf 7�FJLbWR�FK7

LKNJDL�7�NKGIK�FHSGJDE��A���*�e�!�X8`f 7�bDHLHR�FK7

LKNJDL�7�&?�KSLJG��A���*�_` 7�gEGPH�LKc7

LTSHb�b�&?�KSLJGJ�b�QHLNKDJ�&?Ah������� 7�GHaLKMEN�cMKgJMEJ

b�GDJIJ�������*���� 7� H[M\PEN

GgJDgEI��!��

!�����*���� 7�GIKMEL\JNNKGI\�b�FHEGIKa�8

i������� 7� bWaHS� EcdEIPK�FLE�GHbFKSJMEE

������� 7�EMILJNJMDGgJDgEIK

�������!�� 7�FLHSHPjEDUFHEGI����

������ 7� EcbPJgULKMJJ�GHaLKMJMMHJ�cMKgJMEJ�Ec�GDJIK

��!���*��� 7�gEGPH�LKcLTSHb�bKSLJGJ*�HDbJSJMMWa�FHS�aHGDHb\k�gKGDU

������*��� 7�PHOEgJGIER�GSbEOMK�lDH�cMKgJMEJ

��A����*��!������!� 7�bHGGDKMHbEN�GDJI��� 7�bHcbLKD�Ec�Q\MI7

dEE

Page 73: 001 Системный Администратор 10 2002

сети

Число принятых байт (длина принято-го пакета):

Первые 12 байт в принятом буфересодержат MAC - адреса отправителя и по-лучателя. Заполним структуру struct ethhdreth адресной информацией:

По смещению 14 в данном буфере рас-положены данные Ethernet-кадра - IP-па-кет:

Проведем анализ принятого Ethernet-кадра.

версия IP-протокола MAC-адрес отправи-теля:

MAC-адрес получателя:

Прием пакетов осуществляется с по-мощью функции recvfrom. Эта функцияпринимает данные через дескриптор e0_r.Принятое сообщение копируется в струк-туру ip_pack.

В принятом пакете первым следует за-головок Ethernet-кадра. По смещению 14расположен IP-пакет. Поле «Версия» ука-зывает тип данного пакета. Для IPv4-па-кета данное поле содержит значение 4 вдвоичной форме. Значение длины заголов-ка лежит в диапазоне между 20 и 60 байта-ми и находится в поле «Длина заголовка».Поле «Протокол» содержит идентифика-цию протокола следующего, более высо-кого уровня, содержащегося в разделе дан-ных (т.е. в теле сообщения) данного IP-пакета. В документе RFC 1700 перечисле-ны все значения, которые могут содержать-ся в поле «Протокол» в заголовке IP-паке-та. Поле «Адрес источника» и поле «Адресназначения» содержат соответственно IP-адрес отправителя пакета и IP-адрес пред-полагаемого получателя.

Дальнейшая обработка принятого па-кета зависит от полей «Длина заголовка»и «Протокол». В принятом буфере по сме-щению, указанном в поле «Длина заго-ловка» (с учетом заголовка кадра Ethernet)будет расположен заголовок протоколаследующего уровня. Его анализ аналоги-чен вышеприведенному анализу заголов-ка IP.

Для получения исполняемого модулясоздадим Makefile следующего содержания:

В файле ip.c находится главная функцияпрограммы. Командой make мы получим ис-полняемый модуль ip. Команда make cleanудалит все объектные файлы. Результатыработы программы будут отображаться наконсоли. Иногда это не совсем удобно, по-этому, немного модифицировав программу,результаты можно сохранять в файле.

Компиляцию производим с ключем -g длявозможности последующей отладки. Наде-юсь, что читателю это не понадобится, новсе-таки хочу показать простой прием поис-ка неисправностей в программе (не только вэтой). Иногда программа, хотя и компилиру-ется без ошибок, при запуске выдает сооб-щение Segmentation fault и завершается. Длянашего примера, если программа работаетнекорректно, запустите исполняемый файлip на отладку командой gdb ip. В команднойстроке отладчика наберите run и изучитеинформацию, которую выдаст отладчик. Онукажет место, где программа аварийно за-вершилась, и Вам останется только устра-нить неисправность. Если все в порядке, топерекомпилируйте программу с ключем -s.

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

�������"5m�����#�9�m�6*����4�

�������""�����4�:���*�!���*�8`4�

�������""�����4:������*�"!����X�8h4*��������4�

��� ""��� 7�� A������4� n#h4���������

�������"5�9�`�]�9�`�]�9�`�]�9�`�]�9�`�]9�`��m��7��m��5*�����������e3f*� �����������e8f*�����������e`f*�����������e_f*� �����������ehf*�����������eof4�

�������"5�9�`�]�9�`�]�9�`�]�9�`�]�9�`�]9�`�6*���������e3f*� ������ ����e8f*� ���������e`f*����������e_f*�����������ehf*����������eof4�

�������"59��m�6*����7�����4�7�SPEMK�cKOHPHbIK�&?7FKIJDK

�������"59��m�6*�������"��7��������44�7�SPEMK�bGJOH�FKIJDK

������� "59�� m�6*� ��� 7���������4� 7� FLHDHIHPbJLaMJOH�\LHbMT

������� "59�� m�� 7�� m�6*

��������"���7������44� 7� KSLJGEGDHgMEIK

�������"59��m�6*��������"���7������44� 7� KSLJGMKcMKgJMET

��������"84�

��pHNFEPTDHL�q--�#� ��

��pHNFEPTDHL�KGGJN[PJLK'$+2�#����

��rNT�EGFHPMTJNHOH�NHS\PT����#���&?� #� ����� �����������

���������A��� ����������s"���4]�s"&?4

s"--4�7 �7��s"���4�s"&?4����]�����

s"--4�7�����������������]�������������

s"'$+24� 7�� ���������������

���������A��]� ���������A��s"--4�7�� ���������A��

����������]� ����������s"--4�7�� ����������

����]���7�����

Page 74: 001 Системный Администратор 10 2002

72

сети

ВведениеПодавляющее большинство сете-

вых служб использует при работе про-токол TCP. Согласно модели OSI, ТСРявляется протоколом транспортногоуровня. Он обеспечивает надежноедвунаправленное соединение междудвумя процессами; данные передают-ся в обоих направлениях без ошибок,пакеты не теряются и не дублируют-ся, последовательность передачи дан-ных не нарушается.

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

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

ходится в состоянии LISTEN (прослу-шиваться). Быстро определить состо-яние порта позволяет специальноепрограммное обеспечение - сканерпортов.

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

СКАНЕР ПОРТОВ:

ПРИМЕРРЕАЛИЗАЦИИ

ВЛАДИМИР МЕШКОВ

Page 75: 001 Системный Администратор 10 2002

73№1, октябрь 2002

сети

Целью данной статьи являетсяописание принципов функционирова-ния и внутреннего устройства просто-го сканера портов TCP протокола.

Порядок установленияTCP соединения

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

При установлении соединения за-действуются поля «Порядковый но-мер» (SEQ), «Номер подтверждения»(ACK-SEQ), флаги SYN, ACK и RSTзаголовка TCP-пакета. Флаг SYN яв-ляется флагом синхронизации. Ониспользуется при установлении со-единения и устанавливает начальныйпорядковый номер, используемый дляпоследующей передачи данных. ФлагACK указывает на то, что поле номе-ра подтверждения содержит досто-верные данные. Флаг RST использу-ется для сброса соединения.

Соединение устанавливается в 3этапа:� инициатор соединения (клиент)

формирует SYN-пакет (TCP-пакетс установленным флагом SYN), за-полняет поле SEQ и передает па-кет серверу;

� если порт, на который пришел зап-рос на соединение, открыт, серверформирует SYN|ACK-пакет, запол-няет поля SEQ, ACK-SEQ и пере-дает пакет клиенту. Значение поляACK-SEQ равно значению поляSEQ из пакета клиента, увеличен-ному на 1 (т.е. ACK-SEQ-сервера= SEQ-клиента + 1). Если порт зак-рыт, клиенту отправляется RST-пакет;

� получив SYN|ACK-пакет, клиентпроверяет поле ACK-SEQ и высы-лает серверу ACK-пакет. Послеэтого соединение считается уста-новленным и переходит в фазуобмена данными между клиентоми сервером.

Методы сканирования

Существует достаточно большоечисло методов сканирования, каждыйиз которых имеет свои преимуществаи, соответственно, недостатки. Под-робнее о каждом из них можно про-

читать в статье «NESSUS - современ-ный анализ безопасности, методысканирования»(h t tp : / /www.hackzone.ru/articles/nessus.htm#scan), атакже в документации на сканерNmap (http://www.insecure.org/nmap).

Мы рассмотрим один из методов -SYN-сканирование. Этот метод частоназывают half-open (полуоткрытым)сканированием, т.к. полное TCP-со-единение с портом сканируемой ма-шины не устанавливается. Суть дан-ного метода заключается в следую-щем. Вы посылаете TCP-пакет с ус-тановленным флагом SYN, как еслибы собирались установить реальноесоединение с выбранным портом, иожидаете ответ. Принятый пакет с ус-тановленными флагами SYN и ACKуказывает на то, что выбранный портоткрыт и ожидает соединения. ФлагRST означает обратное. Если полученSYN|ACK-пакет, следует немедленноотправить пакет с флагом RST длясброса соединения, хотя реально завас это сделает ядро. Преимуществомданной технологии является отсут-ствие в log-файлах сканируемой ма-шины записей о попытках установле-ния соединения с ней. Недостаток -необходимость наличия прав root дляформирования SYN-пакета.

Пример реализациисканера

Приведенный ниже код был разра-ботан и протестирован в ОС GNU/Linux, дистрибутив Slackware 7.1, ком-пилятор gcc-2.95.2.

Алгоритм реализации следующий:� определить необходимые пере-

менные и заголовочные файлы;� создать сокеты для приема и пе-

редачи пакетов;� сформировать SYN-пакет и отпра-

вить его сканируемому хосту;� принять ответный пакет и проана-

лизировать состояние флаговSYN, ACK, RST;

� сделать вывод о статусе проверя-емого порта.

Заголовочные файлы ипеременные

Заголовочные файлы и перемен-ные разместим в файле, который на-зовем scan.h. Для работы нам пона-

добятся следующие header-файлы:

структуры:

и переменные:

Сокет для передачи

Дескриптор сокета для передачиполучим при помощи функцииgetsock_send, приведенной ниже.

Необходимые заголовочные файлы:

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

������������ �������������������������������� ������������������������������������ �������������������� ������������������������������������������������������������������������������������������������������������

��������������� � ��� !� �" #$%&�"'(')%*"�"+(��,-�(�(-,.,)'�(�/(0�"

�������������� ���� !� �"1�,#(��2"3"%4".,$,-,!56�*"!(�"

��������������� ���� !� �"1�,#(��2"3"%4".,$,-,!786�*"!(�"

������� ��9������� �9����� !� �"1�,#(�2"3"%"#�(�' :)'/,�+";):,$,!"$<�',0�)��(+(

������� ��9�������������� !� �"1�,#(�2"3"%"#�(�' :)'/,�+";):,= #"�$('',0�)��(+(

����������9���>��� �?��9���@��� �?��9���@����9�A��B@����9��� � � �@��������?��@

C������ �*�(-#,4".,$,-,!�D(,=&,�

#)+*�)�"�E(�(!,'��,$<',0� ++F786�*"!(�"G-4%�)4)�&,#'F&�(!��,-�!"'(��"HI9�J

��� ���#(�!�)*�,�-�*,+,."�($<',.,�,!(�"�B���#(�!�)*�,��,!(�"#$%*(�(#"E)�B���#(�!�)*�,��,!(�"#$%*�)(+"�����E)�$,*(�(#"''F&="0�����E)�$,*�)'%�F&="0�� ���',+(��!"')� (+,.,*,��"������)'#(!�)'�(�/(0�"1E(�(4!,�,�F0,� 3(��-$%(��%�!"')�,-"')(�����9���9�����*"!(�1*(�(#"-"(+F0-�(�<�

������������ ������������������������������������ �������������������������������������������������������������������������?��� �������G��9������J

�-F4,-/ '!;))

Page 76: 001 Системный Администратор 10 2002

74

сети

Переменные:

Сокет создадим следующим сис-темным вызовом:

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

Сокеты типа SOCK_RAW (RAW-сокеты) домена AF_INET удобны тем,что позволяют получить непосред-ственный доступ к служебным полямпротокола TCP/IP, в отличии от типовSOCK_STREAM и SOCK_DGRAM (дляTCP и UDP соединений, соответствен-но). Существуют также пакетные со-кеты, о которых я рассказывал в ста-тье «Анализатор сетевого траффи-ка», на них мы сейчас останавливать-ся не будем.

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

Опция IP_HDRINCL является опци-ей протокола IP, поэтому параметрlevel вызова setsockopt равенIPPROTO_IP. Если опция IP_HDRINCLустановлена, приложение строит ивставляет в исходящий пакет полныйIP заголовок. Данная опция включа-ется ненулевым значением (const inton=1).

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

Опция SO_BINDTODEVICE являет-ся опцией сокета, параметр level вы-зова setsockopt принимает значениеSOL_SOCKET.

Опция SO_BINDTODEVICE исполь-зует экземпляр структуры ifreq. Вызовsetsockopt считывает из буфера дан-ной структуры имя интерфейса, припомощи которого будут обслуживать-ся все доступы к рассматриваемомусокету. Поэтому вначале мы заполня-ем соответствующее поле структурыifreq именем интерфейса, которыйбыл передан как параметр функцииgetsock_send.

Если все успешно, возвращаем вглавную функцию дескриптор сокета:return ( fd ).

Сокет для приема

Дескриптор сокета для приемаполучим при помощи функцииgetsock_recv (пример данной функциибыл рассмотрен ранее в статье «Ана-лизатор сетевого траффика»).

Заголовочные файлы:

Функция getsock_recv принимает вкачестве параметра индекс интер-фейса и возвращает дескриптор со-кета.

Дескриптор сокета:

Структура для хранения адреснойинформации об интерфейсе (см. файл<linux/if_packet.h>):

Создадим пакетный сокет:

Пакетный сокет имеет типSOCK_DGRAM. Это означает, что за-головок физического уровня (MAC-адрес в случае Ethernet) будет отбро-шен при приеме.

Выделим память для структурыstruct sockaddr_ll s_ll:

Заполним поля структуры s_ll не-обходимыми значениями:

Для получения пакетов только сопределенного интерфейса использу-ется функция bind: таким образом мысоединяем пакетный сокет с интер-фейсом, номер которого указан вструктуре struct sockaddr_ll s_ll.

Привяжем сокет к интерфейсу:

Возвратим дескриптор сокета ввызывающую функцию:

Главная функция

Главной функции мы передаем двапараметра: IP-адрес сканируемогохоста (аргумент argv[1]) и номер пор-та (аргумент argv[2]). Обработкойошибочного ввода параметров будетзаниматься функция usage ():

Первое, что необходимо сделать

������#(�!�)*�,��,!(�"� ������ �KL�/$".-!$:E(')%4".,�

$,-!"G�+�')2(J������������������ !� �"#$%&�"�

'(')%*"�"+(��,-�(�(-,.,)'�(�/(0�"�

�� GG �� K � ���� G MN�5HO71PQ8R�SMT1�� ��GO7U�6�56JJJBJ>

���� �GV� ����WJ@������G�LJ@

C

�������G���������9I�1VX�W1����J@

��������������������������������� ������������������� ���������������������9��������������������������������

���?��� ������YG��������J�-F4,-/ '!;))

��� ��@

��G���� �� ��G��1566SQ7Q�56156�UZS5H8[1G� ���Y ���J\ �1��A� �G �JJBJ>

���� � G V���� �� ��56�UZS5H8[WJ@

�� ��G��J@������G�LJ@

C

������� ��9����������@

�� GG ��K � ���� GPQ8R�6M8RO71PQ8R�Z]SM^1�� ��GO7U�6�M[[JJJBJ

>���� �GV� ����WJ@

������G�LJ@C

I�I���G\����1B1��A� �G������� ��9������JJ@

�� GG���� G��1 G������ � ��9��� �J\����1��A� �G������� ��9������JJBJ>

���� �GV����WJ@�� ��G��J@������G�LJ@

C

����������9I���K6N�6M8RO7@��)*�,!(�"

����������� � � � K �� ��GO7U�6�M[[J@ ��)**�)')+"(+,.,*�,��,!,$"

����������������K�����@�',+(�)'�(�/(0�"����������������K6M8RO7�UQP7@

��)**"!(�"G#$%$,!"$<',0+"_)'FJ

������G��J

��������V��9���W �/"0$�*(�(+(''F�+))��9����/"0$"+)

���I9��G���9�?�1��9��9�?Y`aJ�-F4,-.$"-',0/ '!;))

Y ����9?�GJ>������ G V b� ��9� ` �����56 a `

������ ��ab�WJ@������@

C

��G���� �� ��G��1PQ[�PQ8RO71PQ�c5HZ7QZOd58O1 GY �� �J\���1 ��A� �G���JJBJ>

���� �GVPQ�c5HZ7QZOd58OWJ@

�� ��G��J@������G�LJ@

C

Page 77: 001 Системный Администратор 10 2002

75№1, октябрь 2002

сети

при запуске программы, это прове-рить, все ли необходимые параметрыуказаны:

Преобразуем введенные строко-вые значения адреса и порта в сете-вой формат и заполним адреснуюструктуру удаленной системы:

Тоже самое проделаем для ло-кального хоста.

Получим IP-адрес интерфейса изанесем его в адресную структуруlocal:

Получим индекс интерфейса:

Выделим память для храненияданных, передаваемых и принимае-мых из сети. Пакет будет состоятьтолько из заголовков IP и TCP прото-колов.

Внутри общего пакета разместимслужебные заголовки IP и TCP прото-колов, а также псевдозаголовок.

Заполним поля псевдозаголовканеобходимыми значениями.

Сформируем TCP заголовок.

Алгоритм расчета контрольнойсуммы для заголовков TCP и IP оди-наковый и будет изложен ниже.

Сформируем IP заголовок.

Некоторые поля заголовков (на-пример, поле «Начальный порядко-вый номер» TCP заголовка и поле«Идентификация» заголовка IP) быливыбраны совершенно произвольно,т.к. в данном случае эти значения нина что не влияют.

Отобразим для контроля имеющу-юся адресную информацию:

Создадим сокеты для передачи иприема пакетов.

Передадим сформированныйSYN-пакет хосту назначения.

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

Число 1500 определяет макси-мальный размер MTU для сетиEthernet. Больше этого значения водном пакете принять мы не можем,и любое превышение данного преде-ла трактуется как ошибка.

Теперь займемся анализом приня-того пакета.

Для начала проверим соответ-ствие версии протокола IP. Поле«Версия» должно содержать 4. Еслиэто не так (к нам мог поступить ARP-запрос, который мы не собираемсяобрабатывать), то принятый пакет от-

��G9�?�eKfJ>��9?�GJ@����GLJ@

C

I�I���G\� �9�1B1��A� �G������� ��9������JJ@

� ��K9� �G9�?Y`gaJ@I�I���G\����1B1��A� �G������� ��9������JJ@���������9������9���K������� 9G9�?Y`LaJ@���������� ��K�� ��G� ��J@

��K� ����GMN�5HO71PQ8R�Z]SM^1BJ@

������� G ��� �� �����9I�1 VX�W1V���BWJ@

���G��1P5Q8]5NMZZS1���J@I�I���GG��9��J\� �9�1G��9��J\G

��� �� ����9��� J1 ��A� � G ������� ��9���JJ@

� �9������� ��K�� ��GhfJ@

� ���G��1P5Q8]5N5HZOi1���J@�����K������������@

�9����KG����9��JI9�� �G��A� �G�����������Jj��A� �G������������JJ@

��KG������������J�9����@�� K G ������ ������ � J G�9���� j

��A� �G�����������JJ@����� KG����������9����JG�9����

j��A� �G�����������J���A� �G����������9���JJ@

I�I���G����� 1B1��A� �G������

I�I���G��1B1��A� �G������������JJ@ �,=' $)+��� !� �

����� ����K� �9������� ��@ �$,!"$<'F0*,��

��������K���������� ��@� #"$(''F0*,��

�������K�� ��GLLhkglBfmnJ@�'"E"$<'F0*,�%#!,-F0',+(�

����9������KB@ �',+(�*,#�-(�2#(')%

����� ��Kh@ �#$)'"4".,$,-!"G-fg�&�"4�%#'F&�$,�-"&J

�������KL@ � ��"',-)�</$".PoH

����p��� pK�� ��GfBlgJ@ ��"4+(�,!'"

���������KB@ �,=' $)�<*,$(!,'��,$<',0� ++F

���������K�������IGG���� ���J����� 1��A� �G������������Jj��A� �G����������9���JJ@

I�I���G��1B1��A� �G�����������JJ@ �,=' $)+��� !� �

����Y���� �Km@�-(��)%*�,�,!,$"

�������Kh@ �#$)'"4".,$,-!"GE)�$,fg�&=)�'F&�$,-J

�� �� � ����� K �� �� G��A� �G�����������Jj��A� �G������������JJ@�#$)'"*"!(�"

������KfgnB@�*,�%#!,-F0',+(�*"!(�"G)#('�)/)!"�;)%J

�������Kmg@�-�(+%2)4')

������ � � �Kk@���"'�*,��'F0*�,�,!,$G786J

�� �� �9��� K� �9������9������9���@ �$,!"$<'F0"#�(�

�����9���K���������9������9���@� #"$(''F0"#�(�

���������K�������IGG���� ���J��1��A� �G�����������JJ@ �!,'��,$<'"%� ++"

������GV56�"#�(�'"4'"E(')%b��b�X�b�V1������� 9G�����9���JJ@

������GV56�"#�(�)��,E')!"b��b�X�b�V1������� 9G�����9���JJ@

������GVq,��'"4'"E(')%b�b��b�X�b�V1�� ��G��������JJ@

������GVq,��)��,E')!"b�b��b�X�b�V1�� ��G����� ����JJ@

��GG�B��K?��� �������GV���BWJJBJ>

���� �GV?��� �������WJ@����GLJ@

C

��GG�B��K?��� ������YG�����JJBJ>

���� �GV?��� ������YWJ@����GLJ@

C

� �G@@J>

�A�� G�9����1��A� �G�9����JJ@���KB@

��� K ���Y�� I G �B��1 G��9� �J�9����1��A� �G�����������Jj��A� �G������������J1

B1 Hr[[1Hr[[J@

��G���Bss����LhBBJ>���� �GV���Y�� IWJ@����GLJ@

C

����������9I���KMN�5HO7@���� K ����� G �B��1 G��9� �J

�9����1 �� �� G �� �� � �����J1 B1 G������� ��9����J\����1

��A� � G������� ��9������JJ@

��G����KBJ>���� �GV����� WJ@����GLJ@

C������GVb�q(�(#"',X�="0�b�W1

����J@

����9���JJ@ �,=' $)+��� !� ��

����� �� ��9��� K� �9������9������9���@ �"#�(�$,!"$<',.,&,��"

����� �� ��9��� K���������9������9���@ �"#�(� #"$('',.,&,��"

����� ���� � � �Kk@�*�,�,!,$G786J

����� �����?��K�� ��G��A� �G������������JJ@ �#$)'"*�(-#,4".,�$,-!"

Page 78: 001 Системный Администратор 10 2002

76

сети

брасывается и продолжается ожида-ние:

Также мы не будем обрабатыватьIP-пакеты, отправителем которых неявляется сканируемый хост:

и если транспортный протокол не естьTCP:

Если принятый пакет соответству-ет всем условиям, то нам останетсятолько отобразить результаты:

Здесь все предельно ясно. Послеэтого мы прерываем цикл приема па-кетов и выходим из программы.

Сброс соединения возложим наядро.

Контрольная сумма

Расчет контрольной суммы выпол-няет следующая функция:

Код для расчета контрольной сум-мы взят из исходных текстов сканераNmap, поэтому приводится без ком-ментариев. Порядок расчета конт-рольной суммы изложен в RFC 1071.

��GG����Y���� �JeKmJ� ������@

�� GG �� �� �9��� eK���������9������9���J� ������@

��GG������ � � �eKkJ� ������@

�������������������������Lk�������IG���Lk����1���

������J>

��?��������fg��I@���Lk ������@��?��������Lk9��p��@

��IKB@p����G�������LJ>

��IjK����jj@�������Kg@

C

��G������KKLJ> �������KB@�GG����?�����9�

�J\ ������JK�G����?�����9��J���@��IjK ������@

C

��IKG��I��LkJjG��I\B�NNNNJ@

��IjKG��I��LkJ@9��p��Kt��I@������G9��p��J@

C

���9�@C������GLJ@C

������GVq�)'%�,X�="0�b�b�V1���J@������GVX�b���b�V1������� 9G�����9���JJ@������GVX�b�b�b�V1������� 9G�����9���JJ@������GVu(��)%b�b�b�KX�b�W1����Y���� �J@������GVv$)'"4".,$,-!"b�b�KX�b�W1�������J@������ G Vv$)'" *"!(�" b� b�K X� b�W1�� ��G����� �����JJ@������GVw#('�)/)!"�,�b�b�KX�b�W1������J@������GVu�(+%2)4')b�b�KX�b�W1�������J@������GVq�,�,!,$b�b�KX�b�W1������ � � �J@������ G Vx,'��,$<'"% � ++" 56 b�K X�b�W1���������J@������GVq,��)��,E')!b�b�KX�b�W1�� ��G����� ����JJ@������GVq,��'"4'"E(')%b�b�KX�b�W1�� ��G��������JJ@������GVx,'��,$<'"%� ++"786b�KX�b�W1���������J@������GVPOyb�b�b�KX��b�W1�� ��G�������JJ@������ G VM8R�POy b� b� b� K X�� b�W1�� ��G����9������JJ@��G�������KKLJ������GVz$".PoH ��"',-$('b�WJ@��G����9��KKLJ������GVz$".M8R ��"',-$('b�WJ@��G�������KKLJ������GVz$".N5H ��"',-$('b�WJ@��G�������KKLJ������GVz$".SP7 ��"',-$('b�WJ@��G�������KKLJ������GVz$".6rPU ��"',-$('b�WJ@��G������?KKLJ������GVz$".rS] ��"',-$('b�WJ@�� GG �� �� ��� KK L J\\G����9��KKLJJ������GVq,��X�,�!�F�b�W1�� ��G����� ����JJ@

88K?���9I�K��9�P8MH K ��9�� �������I�

?��� �������� ?��� ������Y� {G�9I�J|{GP8MHJ

{G88J�?� {G�9I�J{GHM^OJ

��9�� |��9���{G88J����9���

�������I� |�������I��{G88J���������I��

?��� �������� |?��� ���������{G88J��?��� ���������

?��� ������Y� |?��� ������Y��{G88J��?��� ������Y��

���9�|�I����

Makefile

Для сборки выполняемого модулясоздадим Makefile следующего содер-жания:

Для получения исполняемого мо-дуля достаточно ввести командуmake. После этого в каталоге, где раз-мещены файлы программы, появить-ся файл scan. При запуске в команд-ной строке модуля необходимо ука-зать IP-адрес сканируемого хоста иномер проверяемого порта.

Вот в принципе и все.Обо всех замечаниях и пожелани-

ях пишите на [email protected].

Page 79: 001 Системный Администратор 10 2002

FAQ PERL

Можно лискомпилировать из Perlисполняемый файл?

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

Perl2Exe может сгенерироватьмодули для Win32 и многих клоновUnix.

Perl2Exe также позволяет Вамсоздавать не консольные програм-мы, с использованием Tk.

h t tp : / /www. ind igos ta r . com/perl2exe.htm — разработчик —IndigoSTAR Software.

Еще один продукт IndigoSTARSoftware — SendMail forWindows(TM) — Windows версия по-пулярной программы Unix Sendmail.Она позволяет отправлять сообще-ний из командной строки, CGI сце-нария или BAT-файла.

Как удалить деревокаталогов?

В «Perl Cookbook» by TomChristiansen and Nathan Torkington,O’Reilly («Библиотека программис-та: Perl», издательство «Питер»),приводится два примера рекурсив-ного удаления каталога вместе сего содержимым. В одном исполь-зуется функция finddepth из моду-ля File::Find, во втором - функцияrmtree из File::Path.

Вот еще один способ:

# в качестве параметров скриптпринимает

# список директорий для удале-ния

��� V��9?�| {B ���L� `���g� ������H�ab�W������}MS]d@

� ��9��{�9��G}MS]dJ>����� ����G{�9��J@C

�������� ����>I�{���K�����@������B������{���@I�G}����1}�����1{�����9I�1

{��p���1{����J@

������GZ5S1{���J �Gp9��V89�~��I���{���|{eW9��������BJ@

}����K?���>eG��b��J\\��V{����{�WC��9����GZ5SJ@

��p������GZ5SJ@}�����K?���>eG��b�Gb�J�{�J\\��

V{����{�WC��9����GZ5SJ@�� �����GZ5SJ@

� �{����GB��{�����J>{��p���K{����W�W�{����`{����a@����� ����G{��p���J@

C� �{����GB��{������J>

{�����9I�K{����W�W�{�����`{����a@������{�����9I� �Gp9��V89�~�

������{�����9I�|{eW9������J@C�I���{��� �Gp9��V89�~��I���{���|

{eW9��������BJ@������L@C

по материалам www.xpoint.ruсоставил Дмитрий Горяинов

Proc::Background —Общий ли для Unix иWin32 интерфейсуправление фоновымипроцессами?

Это общий интерфейс для уп-равления фоновыми процессамикак на Unix, так и на Win32 плат-формах. Модуль позволяет Вам за-пускать и завершать фоновые про-цессы, получать выходные данныеи отслеживать состояние фоновыхпроцессов.

P.S. Рекомендую при использо-вании под Win32 брать архив соCPAN и посмотреть прилагаемыепримеры и скрипты.

Proc::Background — http://search.cpan.org/search?dist=Proc-Background

Как можностандартизировать(оформить в видепроцедуры) получениевыборки из БД, чтобыполучать набор записейс именованнымиполями?

Это можно сделать так:

Комментарии:

���y����M��9�Q�U9����

I�G{Zc1{�����JK}�@I�G{������1{�9�9��9��1}���I�1{���1{Y9�1X�9��J@

{������K{Zc������9��G{�����J@{��������������� �������@ p���� G{�9�9��9��K{�������

������� p��9�����J

X�9��KX{�9�9��9��@����}���I�1>X�9��C@C{��������������@}���I�@C

{�9�9��9�����F$!"'"&�_X{�9�9��9��KKX>{�9�9��9��C�*,$ �

E(')(�"+,.,&�_")4��F$!)>X�9��C K �"4)+(',-"''F0 &�_ � E�,=

*,$ E)$�%+"��)-&�_(01"'(*�,��,,#)'+"��)-

}���I�-#"'',+�$ E"(KK������}���I�

q�)+(�)�*,$<4,-"')%|���Zc5@���{���KZc5��� �����G�Zc5|I����|I����|� �9�� ���1{����1{�9��p ��1>S9���O�� �K�LCJ ����V� �������?|{Zc5||������b�W@

}���Ky����M��9�Q�U9����G{���1V����������1�9��p ���� I����WJ@

� �G{�KB@{�K{����@{�jjJ>�����Vb�`S�� ���{�a||b�W@� ��9�� {��� G� �� ����

X>{���`{�aCJ>�4"*)�<-)#"{9`La>�C�!-)-"$('�

�'"{9`La��>�C�����{���1Vb�W1{���`{�a>{���C1

Vb�W@CC

{��������� �����@

77№1, октябрь 2002

Page 80: 001 Системный Администратор 10 2002

ВСЕВОЛОД СТАХОВ

ПРОГРАММИРОВАНИЕСОКЕТОВ

Page 81: 001 Системный Администратор 10 2002

79

сети

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

Параметр domain задаёт тип транспортного прото-кола, т.е. протокола доставки пакетов в сети. В настоя-щее время поддерживаются следующие протоколы (ноучтите, что для разных типов протокола тип адреснойструктуры будет разный):

Поддерживаются и другие протоколы, но эти 4 явля-ются самыми популярными.

Параметр type означает тип сокета, т.е. то, как бу-дут передаваться данные: обычно применяется констан-та SOCK_STREAM, её использование означает безопас-ную передачу данных двунаправленным потоком с кон-тролем ошибок. При таком способе передачи данныхпрограммисту не приходится заботиться об обработкеошибок сети, хотя это не уберегает от логических оши-бок, что актуально для сетевого сервера.

Параметр protocol определяет конкретный тип про-токола для данного domain, например IPPROTO_TCPили IPPROTO_UDP (параметр type должен в данномслучае быть SOCK_DGRAM).

Функция socket просто создаёт конечную точку и воз-вращает дескриптор сокета; до того, как сокет не со-единён с удалённым адресом функцией connect, дан-ные через него пересылать нельзя! Если пакеты теря-ются в сети, т.е. произошло нарушение связи, то при-ложению, создавшему сокет, посылается сигнал BrokenPipe — SIGPIPE, поэтому целесообразно присвоить об-работчик данному сигналу функцией signal. После того,как сокет соединён с другим функцией connect, по немуможно пересылать данные либо стандартными функ-циями read — write, либо специализированными recv —send. После окончания работы сокет надо закрыть фун-кцией close. Для создания клиентского приложения до-статочно связать локальный сокет с удалённым (сер-верным) функцией connect. Формат этой функции та-кой:

При ошибке функция возвращает -1, статус ошибки

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

���������������� ���������������������������

����������������������������������������� �������� �������������� ��������

�������� ! ����"#$%" &'()!*+),� ('--.+ ()/ ,� 0!,� 12���3 � 4'0'5+67�

�����89 ���:�� ��� 4;'<'('!� �������� +) =5'!>>� ;)?4;'?<;)+@+� ?>AB)?CD=75 <+6A�)0;>?�

�����89E ���E�� ?!>0.FG>>� 4'('!>+ >� 4;'<'=('!)������H��=�IDJ�5 <+6A�)0;>?

������ ����=�4;'<'('!6������

Page 82: 001 Системный Администратор 10 2002

80

сети

можно получить средствами операционной системы.При успешной работе возвращается 0. Сокет, однаждысвязанный, чаще всего не может быть связан снова, так,например, происходит в протоколе ip. Параметр sock_fdзадаёт дескриптор сокета, структура serv_addr назна-чает удалённый адрес конечной точки, addr_len содер-жит длину serv_addr (тип socketlen_t имеет историчес-кое происхождение, обычно он совпадает с типом int).Самый важный параметр в этой функции — адрес уда-лённого сокета. Он, естественно, неодинаков для раз-ных протоколов, поэтому я опишу здесь структуру ад-реса только для ip(v4) протокола. Для этого использу-ется специализированная структура sockaddr_in (её не-обходимо прямо приводить к типу sockaddr при вызовеconnect). Поля данной структуры выглядят следующимобразом:

Обратите внимание на особый порядок байт во всехцелых полях. Для перевода номера порта в сетевой по-рядок байт можно воспользоваться макросом htons(unsigned short port). Очень важно использовать имен-но этот тип целого — беззнаковое короткое целое.

Адреса IPv4 делятся на одиночные, широковеща-тельные (broadcast) и групповые (multicast). Каждыйодиночный адрес указывает на один интерфейс хоста,широковещательные адреса указывают на все хосты всети, а групповые адреса соответствуют всем хостамв группе (multicast group). В структуре in_addr можноназначать любой из этих адресов. Но для сокетных кли-ентов в подавляющем большинстве случаев присваи-вают одиночный адрес. Исключением является тот слу-чай, когда необходимо просканировать всю локальнуюсеть в поисках сервера, тогда можно использовать вкачестве адреса широковещательный. Затем, скореевсего, сервер должен сообщить свой реальный ip ад-рес и сокет для дальнейшей передачи данных долженприсоединяться именно к нему. Передача данных че-рез широковещательные адреса не есть хорошая идея,так как неизвестно, какой именно сервер обрабатыва-ет запрос. Поэтому в настоящее время сокеты, ориен-тированные на соединение, могут использовать лишьодиночные адреса. Для сокетных серверов, ориентиро-ванных на прослушивание адреса, наблюдается другаяситуация: здесь разрешено использовать широковеща-тельные адреса, чтобы сразу же ответить клиенту назапрос о местоположении сервера. Но обо всём по по-рядку. Как вы заметили, в структуре sockaddr_in полеip адреса представлено как беззнаковое длинное це-лое, а мы привыкли к адресам либо в формате x.x.x.x

(172.16.163.89) либо в символьном формате(myhost.com). Для преобразования первого служит фун-кция inet_addr (const char *ip_addr), а для второго — фун-кция gethostbyname (const char *host). Рассмотрим обеиз них:

— возвращает сразу же целое, пригодное для исполь-зования в структуре sockaddr_in по ip адресу, передан-ному ей в формате x.x.x.x. При возникновении ошибкивозвращается значение INADDR_NONE.

— возвращает структуру информации о хосте, исходяиз его имени. В случае неудачи возвращает NULL. По-иск имени происходит вначале в файле hosts, а затем вDNS. Структура HOSTENT предоставляет информациюо требуемом хосте. Из всех её полей наиболее значи-тельным является поле char **h_addr_list, представля-ющее список ip адресов данного хоста. Обычно исполь-зуется h_addr_list[0], представляющая первый ip адресхоста, для этого можно также использовать выражениеh_addr. После выполнения функции gethostbyname всписке h_addr_list структуры HOSTENT оказываютсяпростые символические ip адреса, поэтому необходи-мо воспользоваться дополнительно функцией inet_addrдля преобразования в формат sockaddr_in.

Итак, мы связали клиентский сокет с серверным фун-кцией connect. Далее можно использовать функции пе-редачи данных. Для этого можно использовать либостандартные функции низкоуровневого ввода/выводадля файлов, так как сокет — это, по сути дела файло-вый дескриптор. К сожалению, для разных операцион-ных систем функции низкоуровневой работы с файла-ми могут различаться, поэтому надо посмотреть руко-водство к своей операционной системе. Учтите, что пе-редача данных по сети может закончиться сигналомSIGPIPE, и функции чтения/записи вернут ошибку. Все-гда нужно помнить о проверке ошибок, кроме того,нельзя забывать о том, что передача данных по сетиможет быть очень медленной, а функции ввода/выводаявляются синхронными, и это может вызвать существен-ные задержки в работе программы.

Для передачи данных между сокетами существуютспециальные функции, единые для всех ОС — это фун-кции семейства recv и send. Формат их очень похож:

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

������� ���� ������K� �� ������ ����� �����

L�'4;>0>!,><�?>->A?<M'�)0;>?'M��M?>N0)�0'!O+'�56<*�%����89�����IE�� ���������

L�4';<�?'(><)�M�?><>M'-�4';,0(>�5)A<���������� ��� ���� ����

L�?<;.(<.;)��?'0>;O)G),����)0;>?P�2<;.(<.;)�� '4 ?6M)FG),� ��=)0;>?Q������� ��� ���K

�����CD�� �� ����L����)0;>?�R?'(><)�M�?><>M'-�4';,0(>�5)A<P�

�����CD������� ����������S ������ ����

�������T#U98�9��H�S���V�� ��������S ���S����� ��

�������������������������� � ����W������������� H���L�'<4;)M!,><�5.X>;�� �

�������������������������� � ����W������������� H���L�4; + -)><�5.X>;�� �

Page 83: 001 Системный Администратор 10 2002

81№1, октябрь 2002

сети

параметры передачи (например, включить асинхронныйрежим работы), но для большинства задач достаточнооставить поле флагов нулевым для обычного режимапередачи. При отсылке или приёме данных функцииблокируют выполнение программы до того, как будетотослан весь буфер. А при использовании протоколаtcp/ip от удалённого сокета должен прийти ответ об ус-пешной отправке или приёме данных, иначе пакет пе-ресылается ещё раз. При пересылке данных учитывай-те MTU сети (максимальный размер передаваемого заодин раз кадра). Для разных сетей он может быть раз-ным, например, для сети Ethernet он равен 1500.

Итак, для полноты изложения приведу самый про-стенький пример программы на Си, реализующей со-кетного клиента:

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

сокет, затем ему присваивается локальный адрес фун-кцией bind, при этом можно присвоить сокету широко-вещательный адрес. Затем начинается прослушиваниеадреса функцией listen, запросы на соединение поме-щаются в очередь. То есть функция listen выполняетинициализацию сокета для приёма сообщений. Послеэтого нужно применить функцию accept, которая воз-вращает новый, уже связанный с клиентом сокет. Обыч-но для серверов характерно принимать много соедине-ний через небольшие промежутки времени. Поэтомунужно постоянно проверять очередь входящих соеди-нений функцией accept. Для организации такого пове-дения чаще всего прибегают к возможностям операци-онной системы. Для ОС Windows чаще используетсямногопоточный вариант работы сервера (multi-threaded),после принятия соединения происходит создание ново-го потока в программе, который и обрабатывает сокет.В *nix системах чаще используется порождение дочер-него процесса функцией fork. При этом накладные рас-ходы уменьшены за счёт того, что фактически проис-ходит копия процесса в файловой системе proc. Приэтом все переменные дочернего процесса совпадают сродителем. И дочерний процесс может сразу же обра-батывать входящее соединение. Родительский же про-цесс продолжает прослушивание. Учтите, что порты сномерами от 1 до 1024 являются привилегированнымии их прослушивание не всегда возможно. Ещё один мо-мент: нельзя, чтобы два разных сокета прослушивалиодин и тот же порт по одному и тому же адресу! Дляначала рассмотрим форматы вышеописанных функцийдля создания серверного сокета:

— присваивает сокету локальный адрес для обеспече-ния возможности принимать входящие соединения. Дляадреса можно использовать константу INADDR_ANY, ко-торая позволяет принимать входящие соединения совсех адресов в данной подсети. Формат функции ана-логичен connect. В случае ошибки возвращает отрица-тельное значение.

— функция создаёт очередь входящих сокетов (коли-чество подключений определяется параметром backlog,оно не должно превышать числа SOMAXCONN, кото-рое зависит от ОС). После создания очереди можноожидать соединения функцией accept. Сокеты обычноявляются блокирующими, поэтому выполнение програм-мы приостанавливается, пока соединение не будет при-нято. В случае ошибки возвращается -1.

— функция дожидается входящего соединения (или из-влекает его из очереди соединений) и возвращает но-вый сокет, уже связанный с удалённым клиентом. При

Y������� Z���[�����\S][���2<)+0);<+6>�5 5! '<>( �?'(><'M�0!,�"���3��[Y������� Z��[�����\S][��^!,�12�_����`�� ?4'!*a.A<>�Y������Z`������\S]��[Y������� Z�����\S]

����� ���K�����������b�=I�[��^>?(; 4<';�?'(><)��[�S ��V��cIDJd�[��e()a)<>!*�+)�5.X>;�0!,�4; @-)��[�S ���cd�b�f$������ ��g�f�[��2<;'()�0!,�4>;>0)B �?>;M>;.��[T#U98�9��S�b���""�[��2<;.(<.;)�0!,�4'!.B>+ ,����)0;>?)��[���� ������� ����[��$<;.(<.;)����[���4;'<'('!)��[����H����S���������b�Jh�[��i)4'!+,>-�4'!,�?<;.(<.;6Q��[ ���\����� �����b�%����89� ���\�����������b�S����������

�������b�����������89��U#$j�U9k8%l�����k#9#�9$���[��2'a0)@-�?'(><��[���������bb�=I�[��2'a0)+�! �?'(><��[

������=I�

S� b� H�S���V�� �f```\��S���\���f��[��m'!.B)>-�)0;>?�7'?<)��[��S�bb���""�[��n�>?<*�! �<)('A�)0;>?o��[

������=I� ���\���� ���\�� ���� b� ���� ���S=]S� ��������chd��[��m>;>M'0 -����)0;>?�M�B ?!'��[

���������������� ���� ������ p ����� ��W�� ������[��m6<)>-?,�?'>0 + <?,�?�.0)!@++6-�?'(><'-��[

������=I�[��2'>0 +>+ >�4;'q!'�.?4>q+'�=�4;'0'!O)>-��[

������������������W������h��Z�h�[��m'?6!)>-�.0)!@++'-.�?'(><.�?<;'(.����[

������=I�

�������������V������W��V�����h��Z�h�[��m'!.B)>-�'<M><�'<�.0)!@++'N'�?>;M>;)��[

������=I�

������fk����������H�` �Q�r�f��V����[��s6M'0�5.X>;)�+)�?<)+0);<+6A�M6M'0��[������������[��i)(;6M)>-�?'(><��[

[��^!,�_����`��4; ->+,><?,�X.+(/ ,��������������[������h�

P

�������������������������V ����H��

���� ���������������������������� �������������� �������

�������V��������������������������������� ������������� ��������

Page 84: 001 Системный Администратор 10 2002

82

сети

этом исходный сокет sockfd остается в неизменном со-стоянии. Структура sockaddr заполняется значениямииз удалённого сокета. В случае ошибки возвращается-1.

Итак, приведу пример простого сокетного сервера,использующего функцию fork для создания дочернегопроцесса, обрабатывающего соединение:

При создании потока (thread) для обработки сокетасмотрите руководство к ОС, так как для разных системвызов функции создания потока может существенноразличаться. Но принципы обработки для потока оста-ются теми же. Функции обработки необходимо только

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

Важное замечание для систем Windows. Мною былозамечено, что система сокетов не работает без приме-нения функции WSAStartup для инициализации библио-теки сокетов. Программа с сокетами в ОС Windows дол-жна начинаться так:

И при выходе из программы пропишите следующее:

Так как в основном операции с сокетами являютсяблокирующими, приходится часто прерывать исполне-ние задачи ожиданием синхронизации. Поэтому частов *nix подобных системах избегают блокировки консо-ли созданием особого типа программы — демона. Де-мон не принадлежит виртуальным консолям и возника-ет, когда дочерний процесс вызывает fork, а родитель-ский процесс завершается раньше, чем 2-й дочерний(а это всегда бывает именно таким образом). Послеэтого 2-й дочерний процесс становится основным и неблокирует консоль. Приведу пример такого поведенияпрограммы:

Вот и всё. Я думаю, для создания простенького со-кетного сервера этого достаточно.

_U%t%9%� `� t � �_U%U� ����h3hIhI�� p`� t � ��

����� ���K

����������[��u0>+< X ()<';�0'B>;+>N'�4;'/>??)��[�����������b�=I�[��^>?(; 4<';�?'(><)�0!,�4;'?!.q M)+ ,��[�����������b�=I�[��^>?(; 4<';�?'(><)�0!,�4; @-)��[�S ��V��cIDJd�[��e()a)<>!*�+)�5.X>;�0!,�4; @-)��[�S �����cd�b�vU����� ��g�w�[��2<;'()�0!,�4>;>0)B �?>;M>;.��[T#U98�9��S�b���""�[��2<;.(<.;)�0!,�4'!.B>+ ,����)0;>?)��[���� ������� ����[��$<;.(<.;)����[���4;'<'('!)��[���� ������� � ��������H����S���������b�Jh�[��i)4'!+,>-�4'!,�?<;.(<.;6Q��[ ���\����� �����b�%����89� ���\�����������b�S����������

�������b�����������89��U#$j�U9k8%l�����k#9#�9$���[��2'a0)@-�?'(><��[���������bb�=I�[��2'a0)+�! �?'(><��[

������=I�

���\���� ���\�� ���� b� ��%ttk�%�x�[��2!.q)>-�+)�M?>7�)0;>?)7��[

��V����������� ���� ������ p ����� ��W�� ������[��m; ?M) M)>-�?'(><.�!'()!*+6A�)0;>?��[

������=I���������������� I��[��y)B +)>-�4;'?!.q M)+ >��[

������=I�

��b� ���������������� �������p� �������W��� ������[��m; + -)>-�?'>0 +>+ >��[

����b�������[��4';'O0)>-�0'B>;+ A�4;'/>??��[������bb�h�K

[��z<'�0'B>;+ A�4;'/>??��[

��������V������W��V�����h��Z�h�[��m'?6!)>-�.0)!@++'-.�?'(><.�?<;'(.����[

������=I���������������W��������h��Z�h�[��m'!.B)>-�'<M><�'<�.0)!@++'N'�?>;M>;)��[

������=I�

������vk����������H�` �Q�r�w��V����[��s6M'0�5.X>;)�+)�?<)+0);<+6A�M6M'0��[�������[��i)(;6M)>-�?'(><��[������h�[��s67'0 -� a�0'B>;+>N'�4;'/>??)��[

P

������������[��i)(;6M)>-�?'(><�0!,�4;'?!.q M)+ ,��[������h�

P

_U%$� �����

����b�������[��2'a0)+ >�4>;M'N'�0'B>;+>N'�4;'/>??)��[�������Zh�K[��1q 5()�M6a'M)�������[

������v������H�8�����Q��g�w��3��=I��

P����������{bh��K[��z<'�4>;M6A�;'0 <>!*{��[

������vg�9S������ �� �S��Ig�w��P��K

����b�������[��|)5'<)�I=N'�;'0 <>!,�a)M>;q)><?,��[

[��u�-6�M6a6M)>-�>G@�'0 +�0'B>;+ A�4;'/>??��[�������Zh�K

������v������H������Q��g�w��3��=I��

P����������{bh��K[��z<'�M<';'A�;'0 <>!*��[

������vg�9S������ �� �S��Dg�w��P��K

[��n�M'<�}<'�<'<�?)-6A�D=A�0'B>;+ A�4;'/>??��[

[��m>;>7'0�M�v?<)+0);<+6Aw�;>O -�0>-'+)��[�������[��^)++6A�4;'/>??�?<)+'M <?,�N!)M+6-�M�N;.44>��[�� ��h��[��2<)+0);<+),�-)?()�X)A!'M��[�S���v[w��[��m>;>7'0�M�(';+>M'A�()<)!'N��[� ��������[��2'5?<M>++'�?)-�('0�0>-'+)��[

[��m; �M6a'M>������0>-'+)�4',M!,><?,�4'<'-'(=0>-'+���[P

P

Page 85: 001 Системный Администратор 10 2002

ОБРАЗОВАНИЕ

Page 86: 001 Системный Администратор 10 2002

84

образование

ВЗАИМНЫЕФУНКЦИОНАЛЬНЫЕЗАВИСИМОСТИ

АНДРЕЙ ФИЛИППОВИЧ

Page 87: 001 Системный Администратор 10 2002

85№1, октябрь 2002

образование

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

Теория нормализации (зависимостей) появилась одно-временно с теорией реляционной алгебры. Коддом былипредложены первые нормальные формы. Впоследствии,третья нормальная форма была уточнена и названа нормаль-ной формой Бойса-Кодда (НФБК). Позже Фэйджином (Fagin)были предложены 4 и 5 нормальная формы, а также альтер-нативная доменно-ключевая нормальная форма [3]. Суще-ствуют и другие нормальные формы, но наиболее популяр-ной является 3НФ и НФБК.

В основе теории нормализации лежат различные поня-тия зависимостей между атрибутами БД. В теории Коддаиспользуется понятие функциональной зависимости (ФЗ),реляционный аналог математической функции. Рассмотре-ние основных вопросов статьи требует четкого определе-ния понятия ФЗ, поэтому приведем формальное определе-ние ФЗ из 6-ого издания книги Дейта [4]. Отметим сразу, чтостатья ориентирована на читателя, знакомого с основнымипонятиями реляционной алгебры и теории нормализации.

Пусть R — это отношение, а X и Y — произвольные под-множества множества атрибутов отношения R. Тогда Y фун-кционально зависимо от X (X→Y), тогда и только тогда, ког-да каждое значение множества X отношения R связано вточности с одним значением множества Y отношения R.Иначе говоря, если два кортежа отношения совпадают по X[t

1(X) = t

2(X)], то они также совпадают и по Y [t

1(Y) = t

2(Y)].

X→Y o [t1(X) = t

2(X)] => [t

1(Y) = t

2(Y)]

Возможность применения правилАрмстронгаПроектирование схемы базы данных начинается с опре-

деления универсального отношения, в которое входят всеатрибуты. Для предметной области задается множество ог-раничений с помощью функциональных, многозначных идругих зависимостей. Для вывода новых ФЗ или сокраще-ния их числа используются правила Армстронга. Эти прави-ла общеизвестны и приводятся почти в каждой книге по БД.

Однако ни в одной из них не говорится об ограниченностиих использования. Рассмотрим пример использования пра-вила объединения:

Если A→B, A→С то A→BС.Пусть имеется два простейших отношения ЗАРПЛАТА(-

Сотрудник, Зарплата) и СЧЕТА(Сотрудник, N_Кредитки). Вовторой таблице задаются номера кредитных карточек со-трудников. Предположим, что у Невезинского нет кредитки.Специалист по БД решил оптимизировать структуру и уст-ранить избыточность, пользуясь вышеупомянутым правилом.

Если Сотрудник → Зарплата, Сотрудник → N_Кредиткито Сотрудник → {Зарплата, N_Кредитки}.

Сразу после «оптимизации» в результирующем отноше-нии появится кортеж, который имеет пустое (неопределен-ное) значение. Реляционное отношение, да и ФЗ (A→BС)таких кортежей не поддерживают, поэтому такая запись дол-жна автоматически удалиться1.

Большинство современных СУБД поддерживают трех-значную логику (с использованием Null значений), поэтомузапись может не пропасть. Однако наличие неопределен-ных значений приводит к появлению неоднозначности в зап-росах и программах.

Таким образом, свободно применять правила Армстрон-га можно только для проектируемой БД, не имеющей дан-ных. При реструктуризации необходимо использовать Null-значения.

Это замечание существенно для баз данных с динами-чески изменяемой структурой, к которым можно отнестисовременные объектно-реляционные разработки. Функцио-нальные зависимости являются одними из простейших се-мантических ограничений, поэтому можно смело утверждать,что все рассматриваемые вопросы будут актуальны и дляобъектных СУБД.

Проблемы 3НФ и НФБКПриведение отношений в 3НФ и НФБК направлено на

избавление от транзитивных зависимостей (A→B, B→C =>A→C). 3НФ позволяет удалить транзитивные зависимостинеключевого атрибута (C) от ключевого (A) через другойнеключевой (B). В НФБК запрещаются все зависимости сре-ди ключевых атрибутов и любой неключевой атрибут дол-жен напрямую (нетранзитивно) зависеть от ключа, т.е. от всехключевых атрибутов.

Рассмотрим пример приведения отношения в третьюнормальную форму, предложенный Ульманом[18] и пробле-мы, которые при этом возникают.

Пусть задана схема отношений R и множество функцио-нальных зависимостей F. Звездочкой (*) помечены функци-

Обычно к системному администраторуобращаются по самым разным вопросам,при возникновении любой проблемы: будьэто забытый пароль, неработающаяпрограмма, нечитающаяся дискета илипропавшие неизвестно куда данные. Этотсписок можно продолжать бесконечно.Мне хотелось бы остановиться наошибках, которые возникают при работе сСУБД. Статья посвящена тем, комуприходится заниматься вопросамипроектирования или реструктурированияреляционных баз данных.

��������� ��� ����

����������� �����

�� ��� ����

���������� �����

��������� ����

��������� ����������

�� ��� ������

���������� ������

��������� ������

��������� ��� ���� ����������

����������� ����� ���

�� ��� ���� ������

���������� ����� ������

��������� ���� ������

Page 88: 001 Системный Администратор 10 2002

86

образование

ональные зависимости, которые отсутствуют в указанномпримере.

R = (A, B, C, D, E, T), гдеA – читаемый курс,B – преподаватель,C – час начала занятий,D – аудитория,E – студент,T – оценка по курсу.

F = {CD→B, CD→A, AC→D, CE→A, A→B, CB→D, AE→T,CE→D}

A→B — каждый курс ведет один преподаватель;CD→A — в аудитории в один и тот же момент времени

может читаться только один курс;CB→D — преподаватель в один и тот же момент време-

ни может находиться только в одной аудитории;CE→D — студент в один и тот же момент времени может

находиться только в одной аудитории;AE→T — по каждому курсу каждый студент имеет толь-

ко одну оценку;AC→D* — каждый курс в один и тот же момент времени

может читаться только в одной аудитории;CD→B*— в аудитории в один и тот же момент времени

может быть один преподаватель;CE→A* — каждый студент в один и тот же момент вре-

мени может слушать только один курс.

Для приведения схемы отношения в 3НФ необходимонайти минимальное покрытие множества функциональныхзависимостей. В описываемом примере оно будет представ-лено следующим образом[18]:

F = {A→B, CD→A, CB→D, AE→T, CE→D}Далее, осуществим декомпозицию схемы отношения:

r={AB, CDA, CBD, AET, CED}

Данная схема находится в НФБК и декомпозируется изисходной схемы с сохранением зависимостей. Недостаткомэтой декомпозиции является зависимость проекций (по тер-минологии Риссанена). Отсюда следует, что схема можетобладать аномалиями. Проиллюстрируем это на примере:

На рис.1. представлены три таблицы из полученной схе-мы отношений. Звездочками отмечены ключевые поля.Пусть в БД хранится информация, что в 10 часов в 12 и 13

аудиториях должны читаться кур-сы «Базы данных» и «Операци-онные системы» (CDA). Извест-но, что эти курсы читают соответ-ственно преподаватели Иванов иПетров (AB). При этом оба пре-подавателя должны проводитьзанятия одновременно в однойаудитории (CBD). Данная инфор-мация является противоречивой,несмотря на то, что схема отно-шений находится в НФБК и всеусловия ФЗ соблюдены.

Представим теперь, что D —это номер посадочной полосы са-

молетов с номером рейса из B. По условиям, заданным на-бором ФЗ такая ситуация невозможна. И тем не менее, вБД, находящейся в НФБК с «сохранением» зависимостейсодержится неутешительный приговор двум самолетам.

Рассмотрим другой случай. Пусть D — это сумма в раз-мере 120000$ и ее нужно перечислить только на счет Ива-нова. Как видно из рис.1. эту сумму может также получить иПетров, а также десятки других сотрудников и это не будетпротиворечить структуре БД.

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

Взаимные функциональные зависимостиОставшаяся часть статьи посвящена вопросу обнаруже-

ния и устранения ошибок, описанных выше. Рассматривае-мая противоречивость данных связана с тем, что во множе-стве ФЗ имеются взаимные функциональные зависимости(ВФЗ).

Взаимной функциональной зависимостью атрибутов A иB называется пара функциональных зависимостей видаB→A, A→B и обозначается как A↔B.

Рассмотрим основное свойство ВФЗ. Из функциональ-ной зависимости A→B вытекает утверждение 1. Кроме того,может существовать множество кортежей с разными значе-ниями в атрибуте А и одинаковыми значениями в атрибутеB (утверждение 2):

(1) A→B o [ti(A) = t

j(A)] => [t

i(B) = t

j(B)]

(2) [∀ ti(B)] ∃ {t(A)} , |{t(A)}|?1

Аналогично определим соотношения для ФЗ B→A:(3) B→A o [t

i(B) = t

j(B)] => [t

i(A) = t

j(A)]

(4) [∀ ti(A)] ∃ {t(B)} , |{t(B)}|?1

Соединяя условия (1), (4) и (2), (3) получаем следующие ут-верждения:

(5) [∀ ti(A)] ∃ {t(B)} , |{t(B)}|=1

(6) [∀ ti(B)] ∃ {t(A)} , |{t(A)}|=1

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

Для задания ВФЗ в СУБД необходимо атрибуты A и Bобъединить в одном отношении (таблице) и задать уникаль-ность каждого атрибута. Если части ВФЗ более одного ат-рибута, то можно использовать первичный и альтернатив-ный ключ (с обязательным заданием уникальности).

Надо отметить, что алгоритмы нахождения минимально-го покрытия Мейера [11] и Бернштейна [19] учитывают ВФЗ,но только в рамках сокращения размера покрытия.

Для дальнейшего рассмотрения материала введем по-нятие условной ВФЗ (УВФЗ).

��� ��� ��

��� ��� ������������

��� ��� ���� ���� �

��� ��

������������ �������

���� ���� � � ����

��� ��� ��

��� ������� ���

��� � ���� ���

Рис.1. Противоречивость БД.

Page 89: 001 Системный Администратор 10 2002

87№1, октябрь 2002

образование

Условной взаимной функциональной зависимостью ат-рибутов A и B называется пара функциональных зависимо-стей вида СB→A, СA→B, где С — набор атрибутов (усло-вие) такой, что CCA=?, CCB=?.

Будем обозначать УВФЗ как С|A↔B.

Смысл УВФЗ заключается в том, что при определенныхусловиях атрибуты находятся во взаимной функциональнойзависимости. Из функциональной зависимости CA→B вы-текают утверждения 7 и 8:

(7) CA→B o [ti(C) = t

j(C)]&[t

i(A) = t

j(A)] => [t

i(B) = t

j(B)]

(8) [∀ ti(B)] ∃ {t(СA)} , |{t(СA)}|?1

Аналогично определим соотношения для ФЗ СB→A:(9) СB→A o [t

i(C) = t

j(C)]&[t

i(B) = t

j(B)] => [t

i(A) = t

j(A)]

(10) [∀ ti(A)] ∃ {t(СB)} , |{t(СB)}|?1

Соединяя условия (7-10) и фиксируя значение атрибута С,получаем следующие утверждения:

(11) [∀ ti(A)] ∃ {t(B)} , |{t(B)}|=1

(12) [∀ ti(B)] ∃ {t(A)} , |{t(A)}|=1

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

Существует несколько способов задать УВФЗ. Можноввести понятие условного ключа или условной уникальнос-ти. Проиллюстрируем эти понятия. Пусть имеется условнаявзаимная зависимость (УВФЗ) такая, что условием являет-ся набор атрибутов C, атрибуты B и D входят во ВФЗ. Тогдапри фиксированном значении атрибутов из С значения ат-рибутов B и D являются уникальными. Для пояснения при-ведем пример.

В настоящее время возможность введения таких клю-чей в СУБД отсутствует, поэтому данное ограничение мож-но реализовать либо программным способом, либо деком-позицией отношений и дополнительных изменений схемы.

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

При наборе условных атрибутов (C1,.. Cn) конструкцияWhere изменится:

Альтернативой может послужить общее ограничения нацелостность БД.

Вторым способом задания ограничений является соот-ветствующая организация структуры БД (схемы). Реализо-вать ограничение в одном отношении можно путем заданиядвух ключей (первичного и альтернативного) со свойствомуникальности. Можно также осуществить декомпозицию сиспользованием внешних ключей.

Выявление ВФЗРассмотрим теперь причины возникновения взаимных

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

Следствие 1Во всех функциональных зависимостях, в которых при-

сутствует набор условных атрибутов (С) и условная взаим-ная ФЗ (CA→B, CB→A), можно воспользоваться правиломA~B для нахождения минимального (канонического) покры-тия.

Пример:F = {CD→B, AC→D, CE→A, A→B, CD→A, CB→D, AE→T,

CE→D}CD→B & CB→D => B→D & D→B => C| D↔B

Выберем все зависимости, в которых присутствует C:CD→B, AC→D, CE→A, CD→A, CB→D, CE→D

Заменим B на D и получим:CD→D, AC→D, CE→A, CD→A, CD→D, CE→D

Сократим одинаковые зависимости (CD→D).

Полученная зависимость CD→D является рекурсивной3.В исходных данных такой зависимости нет, поэтому можнопроверить предметную область на ее наличие. В случае ееобнаружения необходимо разбить ее на нерекурсивные за-висимости4. В общем (данном) случае рекурсии нет, поэто-му эту функциональную зависимость исключаем из спискакак тривиальную.

AC→D, CE→A, CD→A, CE→D, C| D↔BАналогично поступаем и AC→D и CD→A

CE→A, C| A↔D↔BИтоговое множество функциональных зависимостей будетвыглядеть следующим образом:

F = { A→B, AE→T, CE→A, C| A↔D↔B}

��������������������� ��� ������������� ������������

��� ��� �������������� ���!����������

������ ������ ���

������ ������� ���

������ �������� ���

��� ��� �������������� ���!����������

����� �� ������ ���

����� �� �������� ���

����������� ��������������� ������������������� �������

����������������������������������������������

������������������������������������ !"#������$� !"#������������������ �����������������������������������������

���������������%�����������&������������������ !"#������$� !"#������������������ �����������������������������������������

Page 90: 001 Системный Администратор 10 2002

88

образование

Следствие 2Более простые УВФЗ включают в себя более сложные.Если имеется две УВФЗ такие, что множество условных

атрибутов одной зависимости входит во множество услов-ных атрибутов другой зависимости, то такая УВФЗ являет-ся более простой:

C|A↔B и D|A↔B, и CID, то C|A↔B => D|A↔B

Следствие 3Нахождение минимального покрытия ФЗ не убирает

и не изменяет ВФЗ, но значительно осложняет их поиск.В качестве примера можно сравнить очевидность ВФЗ

в исходном и нормализированном наборе ФЗ (см. выше).Одним из способов обнаружения ВФЗ является графи-ческое отображение ФЗ и поиск кольцевых структур5.

CA→B, B→AНа рис.2а показаны функциональные зависимости в

графической форме. Можно заметить, что функциональ-ные зависимости пересекаются, и, кроме того, образу-ют циклическую структуру. Воспользовавшись правиломдополнения Армстронга, получаем схему, представлен-ную на рис.2б. Функциональная зависимость B→A пред-ставлена отдельно и атрибут B в ней не зависит от CA,т.к. зависимость была разделена на B→A при наличии Cи на B→A при отсутствии C. На рис.2в представлено вы-деление взаимной зависимости A и B при условии С.

На рисунке 3 рассматривается пример нахожденияУВФЗ для минимального покрытия ФЗ из примера, при-веденного выше. В результате нахождения минимально-го покрытия ВФЗ становятся менее очевидными из-заувеличения элементов в цикле. Взаимные зависимостистановятся транзитивными.

Можно сделать вывод, что нахождение минимально-го покрытия ФЗ усложняет процесс нахождения ВФЗ засчет уменьшения числа зависимостей. Тем не менее, на-хождение минимального покрытия необходимо для по-

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

Ниже приводится алгоритм нахождения ВФЗ для ми-нимального покрытия. Данный алгоритм является схе-матичным и неоптимизированным, т.к. при нахожденииВФЗ не осуществляется изменение (уменьшение) мно-жества исходных ФЗ. Можно также заранее исключитьзависимости, которые точно не образуют ВФЗ. Это такназываемые неприводимые слева ФЗ, т.е. те зависимо-сти, в левой части которых содержатся атрибуты, невстречающиеся в правой части других ФЗ.

Алгоритм можно также применять для произвольно-го множества ФЗ, но в случае минимального покрытияВФЗ будут находится только один раз. Существуют мно-жества ФЗ, которые являются взаимно-независимые.Правила определения таких множеств можно найти в[4,20].

Пусть задана схема отношений R и множество ФЗ Sтакие что:

S ={ X[1]→Y[1]… X[i]→Y[i]… X[n]→Y[n]}, где n — коли-чество ФЗ.

Y[i]∈ R, X[i]⊆ R , т.е. Y является атрибутом, а X — на-бором атрибутов из R.

X[i]= {X[i][1]… X[i][j]… X[i][m]}, где m — Количество ат-рибутов в левой части ФЗ. Для разных ФЗ m может из-меняться.

Алгоритм

��

��

� �

��

Рисунок 3.

Рисунок 2.

'()�*+ � (���,( --�./01�23�4567�89��:�;+ ;����� --�23<5=6>�031/=65>4?�?>@/AB>34�4�1643C���������������������=?5>/�����'()�D+ � (�;�,( --�./01�23�4567�?>@/AB>?7�������:�' E�!) + ����� � --�4FA3@�3<G3H3�/I������������������������������������������?>@/AB>34

'()�J+ � (���,( --�./01�23�4567�89�--�651/�B5134/6�4F231GK6>5K$�>3�43I73LG3�G?1/=/6�031M.643C����5>@B0>B@F

���:*'��' E�!) � ����� N������������--OBG0./K�2@346@K6>�7G3L65>43���G?�G?1/=/6�P89�����������--76L<B����� �/�����2@/�B5134//���������� Q!##�'R�Q *(�E��' E�!) $��������������� �S�� ()��$��S --4355>?G3416G/6�231G3H3�52/50?�89

���T�������T��T--OBG0./K�2@346@K6>�7G3L65>43���G?�G?1/=/6�P89--76L<B��' E�!) �/��*UN E�!) �2@/�B5134//�V�#'R�Q *(�E��' E�!) $��*UN E�!) ��V�#�'()�*+ � (���,( --�./01�23�4567�89:�*'����*UN E�!) ������� N� --651/�2@?4FC�?>@/AB>�4W3����������������������������������</>�--�4�164BX�=?5>M�0?03CY1/A3�89�����:�������V�#+ V�#Z��������*UN E�!) S --�>3�B5134/6�<3231������������������������������������������GK6>5K�<@BH/7/

--?>@/AB>?7/�/I�16������������������������������������������43C�=?5>/��������*'�����' E�!) � ����� N� --651/�2@3/I3[13�����������������������������������������I?031M.64?G/6

����:��,,�\V�#�]��' E�!) �^��*UN E�!) _ --<3A?41K6>����������������������������������������������5K�G34?K�`P89����������������,# ����a���� - -

<?GG?K�89�B<?1K6>5K�/I���������+ �YS --031/=65>43�89�B76GM[?6>5K����T

�������#� --/G?=6�35Bb65>41K6>5K�@60B@5/4GFC�4FI34�������������������<1K�<?1MG6C[6H3�23/50?

?����������A��������������������4

Page 91: 001 Системный Администратор 10 2002

89№1, октябрь 2002

образование

Выводы1. Нахождение ВФЗ позволяет избавиться от проти-

воречивости хранимой информации в БД.2. Одним из способов учета ВФЗ является наложе-

ние ограничений на целостность БД. Для этого введемпонятие «целостности по взаимозависимости».

3. Вторым способом учета ВФЗ является нормали-зация отношений, т.е. приведение БД к соответствую-щей структуре (схеме). Введем понятие взаимно-неза-висимой нормальной формы, если схема отношений неимеет ВФЗ. ВННФ можно рассматривать как синонимпонятия ациклической БД.

4. Приведение отношения к ВННФ можно осуществ-лять независимо от приведения отношения в 1НФ, 2НФ,3НФ, НФБК. Рекомендуется выявлять ВФЗ на этапе на-хождения минимального покрытия.

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

6. Автор не считает, что вопросы, затронутые в этойработе являются научной новизной. Более того, авторуверен, что за такой продолжительный срок существо-вания теории баз данных и теории нормализации, про-блемы ВФЗ были затронуты, а может, и решены. К со-жалению, из всех современных книг по БД, только в кни-ге Дейта и Мейера отдаленно затрагивается этот воп-рос, несмотря на его первостепенную важность. Авторосуществлял поиск и просмотрел большое количестволитературы. На поиск аналогичных разработок было по-трачено время, в 7-8 раз превышающее теоретическуюразработку проблемы ВФЗ. «Если теорему проще до-казать, чем найти описание доказательства, то почемуэто не сделать?»

Автор пытается акцентировать внимание на вопро-сах ВФЗ. Если читатель имеет какую-либо информа-цию по данному вопросу, а также возражения, замеча-ния или дополнения, присылайте их по адресу[email protected].

1 Например, если использовать SQL-инструкциюSelect Сотрудник, Зарплата, N_КредиткиFrom ЗАРПЛАТА AS R1, СЧЕТА AS R2Where R1. Сотрудник = R2. Сотрудник

2 Попытка создать описанную БД с заданием связейв среде ERWin приведет к неудаче.

3 Рекурсивные зависимости невозможны в реляци-онной алгебре, называются тривиальными и исключа-ются из множества ФЗ как избыточные. Следует раз-личать рекурсивные и взаимные зависимости.

4 Программа ERWIN позволяет использовать на ста-дии проектирования рекурсивные неидентифицирую-щие связи.

5 Здесь очень хорошо бы подошло слово замыканиеили рекурсивная связь, но они уже используются и не-сут несколько другую смысловую нагрузку. См. такжециклические БД.

���:����*UN E�!) �+ ����S���,# ����a���� --<?GG?K�89�B<?1K6>5K�/I������+ �YS --031/=65>43�89�B76GM[?6>5K�������������'R�Q *(�E��' E�!) $��*UN E�!) ��V�#�S

���T

������T���T

c/>6@?>B@?+

� d@56GM64� e�f�$� g034164� h�d�� iG>6H@?./K� @?52@6<616GGFWej$�hfA$�c?GM$��kk$�Y�lml�5��n63@/K�G3@7?1/I?.//��5>@��opYl��

�� [email protected]/C�d�d��q5G34F�2@360>/@34?G/K�A?I�<?GGFW�$�r?Y</3�/�54KIM$��kkk$�Y�ss�5��n63@/K�G3@7?1/I?.//��5>@���tY�s��

o� u313534�d�q��dG37?1//�4�@61K./3GGFW�A?I?W�<?GGFW��vB@G?1h`ej$�4F2B50��km�wwm�

l� j6C>�x�jL��P46<6G/6�4�5/5>67F�A?I�<?GGFW$�mY6�/I<?G/6�x�$�y�$�hfA�+�iI<?>61M50/C�<37�\P/1MK75_$��kkk��Y�sls�5��n63@/KG3@7?1/I?.//��5>@���mwYolp���q<G?�/I�G?/A3166�231GFW�0G/H�G?@B55037� KIF06�� 9?>@?H/4?X>5K� 432@35F� ?>37?@GFW� 3>G3[6G/C� /jxz8��P�pY37�/I<?G//�A3166�23<@3AG3�@?557?>@/4?X>5K�432@35F�l/�tz8�

t� jBG?64�h��j35>B2�0�ej�/�>6WG/0?�@?A3>F�4�56>/��y�$�j/?Y13HYyi8i$��kkk$�Y�lm�5�

m� x?1/G/=6G03�c�d��y6>3<F�/�5@6<5>4?�/G>6H@?.//�G63<G3@3<YGFW�A?I�<?GGFW��y�+�z?B0?$�wso�Y�l�l�5�

p� x?@234?�n��e?IF�<?GGFW$�73<61/$�@?I@?A3>0?$�@6?1/I?./K$hfA�$�f/>6@$��kk$�Y�okl�5��n63@/K�G3@7?1/I?.//��5>@��kY�k��Ytz8$�3=6GM�0@?>03�

s� x3GG311/�n�$�e6HH�x�$�h>@?=?G�d��e?IF�<?GGFW��f@360>/@3Y4?G/6$�@6?1/I?./K�/�532@343L<6G/6��n63@/K�/�2@?0>/0?$��Y6�/I<�$y�+_P/1MK75_$��kkk$�Y��k�5��n63@/K�G3@7?1/I?.//��5>@�����Y�ts���Ytz8$�3=6GM�0@?>03$�4�35G34G37$�2@/76@F�

w� x3@G664�P�P�$�u?@664�d�8�$�P?5X>/G�h�P�$�r?CW�P�P��e?IF<?GGFW��iG>61160>B?1MG?K�3A@?A3>0?�/GO3@7?.//��y�+�\z31/<L_��Yot��5�

k� xB1MA?� P�P�$� x34?16450/C� h�h�$� x?K=6G03� h�d�$� h/@3>X0P�q��n63@6>/=650/6�35G34F�2@360>/@34?G/K�32>/7?1MGFW�5>@B0>B@@?52@6<616GGFW�ej�$�y�$�h/G>6H$�www$�mmk�5��n63@/K�G3@7?1/I?Y.//��5>@��mY�l���Yoz8$�83@7?1MG36�32/5?G/6�35Bb65>416G3�4>6@7/G?W�0G/H/�

� y6C6@�j��n63@/K�@61K./3GGFW�A?I�<?GGFW��y�+�y/@$�wsp��Ymks�5��n63@/K�G3@7?1/I?.//�@?50@F4?6>5K�4�{>3C�0G/H6�G?/A3166231G3�� q=6GM� 7G3H3� @6IB1M>?>34$� 54KI?GGFW� 5� 7G3H3IG?=GF7/� /536</G/>61MGF7/� I?4/5/735>K7/�� r?557?>@/4?X>5K� 031M.64F6� />?A1/=GF6�I?4/5/735>/$�?1H3@/>7F�5/G>6I?$�<603723I/.//�/�7G3YH/6� <@BH/6� 432@35F�� xG/H?� <35>?>3=G?� 513LG?K$� >�0�� 443</>5K7G3L65>43�<3231G/>61MGFW�23GK>/C$�/�26@632@6<61KX>5K�G603>3@F62@/4F=GF6�32@6<616G/K�

�� y?@>/G�jL��q@H?G/I?./K�A?I�<?GGFW�4�4F=/51/>61MGFW�5/5Y>67?W���Y6�/I<�$�y�+�y/@$�wsk�

o� r64BG034�u�i�$�|6>46@/034�P�z�$�h?73W4?134�}�z��e?IF�/A?G0/�<?GGFW��y�+�PF5[?K�[031?$�wsp��Y��ls�5�

l� 8@3134��d�$�8@3134��u��e?IF�<?GGFW�4�iG>6@6G6>6+�2@?0>/Y=65036�@B0343<5>43�23�53I<?G/X����Y2@/13L6G/C�5�ej�$�/I<���Y6�$�\rB550?K�r6<?0./K_$��kkk$�Y�lls�5�

t� ~?G56G�u�$�~?G56G�jL��e?IF�<?GGFW��r?I@?A3>0?�/�B2@?416YG/6$�y�$�e/G37$��kkk$�Y�pkl�5��n63@/K�G3@7?1/I?.//��5>@���kkY�k���Ylz8$�3=6GM�0@?>03�

m� �?16G03� y���� y3<61/@34?G/6� 567?G>/0/� 4� ej�� y�+� z?B0?�u1��@6<��O/IY7?>�1/>�$�wsw��Y��ss�5��Y��f@3A167F�/50B55>46GYG3H3�/G>61160>?��

p� `1M7?G�jL�$�`/<37�jL��P46<6G/6�4�5/5>67F�ej��y�+�c3@/$�kkk$�Y�l�k�5��n63@/K�G3@7?1/I?.//��5>@��wlYos���Ytz8$�f6@6Y/I<?G/6� 0G/H/� sk� H3<?� 5� G6A31M[/7/� /I76G6G/K7/�� f@/43<K>5K?1H3@/>7F�2@/46<6G/K�4�z8�

s� `1M7?G� jL�� q5G34F� 5/5>67� A?I� <?GGFW�� Y� y�+� 8/G?G5F� /5>?>/5>/0?$�wso��Y�ool�5��n63@/K�G3@7?1/I?.//��5>@��t�Ysw��Ylz8$�q<G?�/I�G67G3H/W�0G/H$�53<6@L?b?K�7G3L65>43�?1H3@/>734$>63@67$�?05/37�<1K�OBG0./3G?1MGFW�/�7G3H3IG?=GFW�I?4/5/735>6C�

w� �)�� *���������� N�*�*�U��N*),�%();!#��();��#! *(��')(;��R�Q *(�!#����,�Q*��--������)!����(���! !"!����� ;��Y�wpm�����$���l��Y�r���ppY�ws�

�k� �*��!��� ��� ��,��,� � �(;�(�� �� ('� �#! *(��--� ����)!����(���! !"!����� ;���Y�wpp��Y�����$��l��Y�r��opYo�t�

���!�*(#(� ��$� �#J!�(''� ����� �� �();!#� ���)(!QN� (� N�'*�* *(��!�,� N���*U��('��(�Q� R!#��QN;! !�'()��! !"!���� ;��--������)!����(���! !"!����� ;���Y�ws���Y����p$���$Y�����lYtw�

Page 92: 001 Системный Администратор 10 2002

90

Для обмена информацией в элект-ронной коммерции необходим общийязык, с помощью которого компаниимогли бы обмениваться структуриро-ванными данными между своими раз-нотипными компьютерами. ЯзыкInternet первого поколения, HTML, неподходит для этой цели - он описываетформатирование информации, но не еесмысл. И вот появился XML - ExtensibleMarkup Language (расширяемый языкразметки). Как и HTML, он содержиттекст, размеченный тегами. Но теги вXML описывают уже и смысл и струк-туру информации, позволяя напрямуюобрабатывать ее программными сред-ствами. Например, Международныйсовет по прессе и телекоммуникациямнедавно утвердил NewsML как основ-ную систему разметки новостной ин-формации, также был создан MathMLдля математических документов и др.

Однако для конкретного бизнес-при-ложения сам по себе XML еще не от –вет – он лишь основа, на которой этотответ можно построить.

В соответствии с планами, объяв-ленными в июле 2000 года, специалис-тами фирм «1С» и «Extra.RU» при под-держке технических специалистовпредставительства Microsoft в Россииразработаны стандарты обмена ком-мерческой информацией в форматеXML для торговых организаций.

Между компанией Microsoft®, фир-мой «1С» и ведущими отечественнымиИнтернет-компаниями «Port.ru»,«Price.Ru» и «Extra.RU», а также мос-ковским представительством компанииIntel достигнуто соглашение о поддер-жке единого стандарта обмена коммер-ческой информацией в формате XML.

Соглашение о дальнейшем разви-тии и поддержке единого стандарта

предполагает совместную работу спе-циалистов фирм «1С», «Port.ru»,«Price.Ru», «Extra.RU» и компанииMicrosoft над совершенствованиемстандарта, а также предоставлениевсей необходимой информации органи-зациям, которые в дальнейшем захотятподдерживать предлагаемый стандарт.

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

ИспользованиеCommerceMLСегодня рынок Интернет-коммер-

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

стандарт обменакоммерческой информацией в формате XMLстандарт обменакоммерческой информацией в формате XML

РТИЩЕВА ЕЛЕНАВАЛЕРЬЕВНА

CommerceML

Page 93: 001 Системный Администратор 10 2002

91№1, октябрь 2002

образование

компании, созданные непосредствен-но для продажи услуг через Сеть, атакже фирмы, работающие в сфереинформационных технологий. Есте-ственным путем, позволяющим вов-лечь в Интернет–коммерцию широкийкруг традиционных (off-line) торговыхфирм, расширить сферу примененияИнтернет–технологий и продемонст-рировать преимущества этих техноло-гий продавцам и покупателям, явля-ется публикация каталогов фирм наспециализированных Интернет-сай-тах (Web-витринах). Поэтому количе-ство Web-витрин растет, и Интернет-компании заинтересованы в привле-чении как можно большего числа тор-говых организаций. Однако этот про-цесс сдерживается отсутствием стан-дартов и готовых программно-аппа-ратных решений, а также большойтрудоемкостью организации взаимо-действия торговых организаций сWeb-витринами.

Общее описаниестандартаРазработанный стандарт позво-

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

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

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

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

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

Описание схемыCommerceMLПредусматривается использова-

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

Формированиекоммерческихпредложений покаталогуПредложение практически совпа-

дает с одной строкой «обычного»прайс-листа. Предлагается такой-тотовар по такой-то цене, имеющийся вналичии в таком-то количестве. Напри-мер, гречневая крупа по цене 200 руб-лей за мешок, на складе имеется 125мешков. Предложения группируются вПакет предложений, в котором зада-ется общая часть всех предложений(аналог «шапки» прайс-листа).

Для того чтобы получатели пред-ложений могли понять, какой товарпредлагается, последний должен бытьописан. Описание товара и его клас-сификация «складываются» в Ката-

лог. Каталог может быть «внутрен-ним», т.е. вложенным в тот же доку-мент, что и пакет предложений, и со-ставленным непосредственно авто-ром пакета предложений. Он такжеможет быть «внешним» – составлен-ным одной из известных фирм. В этомслучае в пакете предложений огова-ривается, на какой каталог (класси-фикатор) он ориентирован. Для одно-значного определения товара в пос-леднем случае достаточно ссылки(идентификатора товара во внешнемкаталоге), т.е. в тот же документ, чтои пакет предложений, каталог товаровможно вообще не включать. Таким об-разом, каталог товаров можно рас-сматривать как некий классификатор.Следовательно, в каталоге долженбыть оговорен список Свойств (покаким критериям производится клас-сификация). Устойчивые сочетаниясвойств удобно фиксировать в Набо-ры свойств (например, «свойства ви-деомагнитофона», «свойства телеви-зора»). Для указания, какие свойства(или наборы свойств) доступны (мо-гут быть определены, обязательнодолжны быть указаны) для всего ка-талога, для его группы или для от-дельного товара, используются Ссыл-ки на свойства (Ссылки на наборыСвойств). Каталог (классификатор)обычно создается многоуровневым(т.е. имеющим разветвленное деревокатегорий (Групп), к которым можноотнести товар). Иногда однозначнаяклассификация может вызвать зат-руднения, поэтому для удобства раз-решается включать товары сразу внесколько категорий. Но при этомодна из них должна быть выбрана вкачестве «основной». Например, ра-дио-будильник можно отнести как ккатегории «Радиоприемники», так и ккатегории «Будильники», но в первуюочередь, радио-будильник являетсярадиоприемником. При разработкеклассификаторов принято для каждойпозиции указывать Аналоги (напри-мер, для лекарства это – другие ле-карства аналогичного действия, длязапчастей – запчасти, которые мож-но поставить вместо данной).

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

Page 94: 001 Системный Администратор 10 2002

92

образование

обязательность заполнения данногосвойства). Аналогичный тип элемен-та создан и для набора (Ссылка на на-бор свойств).

Для хранения значений свойств, втом числе и дополнительной, не предус-мотренной классификатором информа-ции, служит специальный тип элемен-та ЗначениеСвойства.

В итоге, для опубликования своегопрайс-листа (составления своего паке-та предложений) надо сделать следую-щее.

1. Классифицироватьсвой товарЭто можно сделать:

� путем составления собственногоклассификатора, для чего нужно:1. составить список свойств, по

которым будет производится классифи-кация;

2. объединить устойчивые сочета-ния свойств в наборы свойств;

3. составить иерархический списоккатегорий (групп);

4. отнести каждый товар к однойили нескольким категориям;

5. определить для каждого товараего аналоги.� путем нахождения своих товаров во

внешнем классификаторе.1. если некоторые товары не най-

дены во внешнем классификаторе, тодля них (и только для них!) придетсясоставлять внутренний классификатор.

2. Отправить пакетпредложений1. Если при составлении пакета

предложений оказалось достаточновнешнего классификатора, то отправ-ленный файл будет содержать толькопакет предложений.

2. Если для составления пакета(всего или его части) понадобился внут-ренний классификатор, то в отправля-емый файл придется включить внутрен-ний классификатор.

Обмен документамиВ задачу, решаемую с помощью

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

� Заказ товара� Cчет на оплату� Отпуск товара� Счет-фактура� Возврат товара� Передача товара на реализацию� Возврат товара с реализации� Отчет о продажах комиссионного

товара� Выплата наличных денег� Возврат наличных денег� Выплата безналичных денег� Возврат безналичных денег

Причем для предприятий (фирм) –отправителя и получателя XML-доку-мента – указанные хозяйственные опе-рации представляются разными доку-ментами. Например «Отпуск товара»для отправителя сопровождаетсяоформлением «расходной накладной»(«накладной на отпуск товара»), а дляполучателя – оформлением «приход-ной накладной». Программа автомати-зации учета может, исходя из вида хо-зяйственной операции и роли, котораяуказана для данного предприятия, «по-нять», является ли «собственное пред-приятие» (от лица которого автомати-зируется учет в программе) получате-лем данного документа. Роли предус-мотрены следующие:� Продавец� Покупатель� Плательщик� Получатель

Например, если в обрабатываемом

XML-документе, описывающем «От-пуск товара» роль «собственного пред-приятия» обозначена как «Покупа-тель», то это означает, что XML-доку-мент описывает расходную накладнуюпоставщика, и ее следует импортиро-вать в учетную систему как «наклад-ную на поступление товара».

Примеры соглашений при исполь-зовании данной схемы.

Обозначения«0-1» - атрибут или элемент не

обязателен. Может принимать толькоодно значение;

«1-1» - атрибут или элемент обя-зателен. Может принимать толькоодно значение;

«0-*» - атрибут или элемент не обя-зателен. Может содержать списокзначений;

«1-*» - атрибут или элемент обя-зателен. Может содержать списокзначений.

По умолчанию – все атрибуты иэлементы являются не обязательны-ми и имеют тип «строка», если специ-ально не оговорено другое.

КоммерческаяИнформация(CommerceInfo)Описание: Корневой элемент XML-

документа, описывающего каталог (ка-талоги) товаров, список (списки) пред-ложений. Содержит один или несколь-

�������������� ������������ � �����������

� ����������������� ���� �!��������������������"������������� �� ��

����������������

�������

� ������������������������#���$������

��������������������

�� ��

� ������������

����������

� ��������������������������������������

��������������������������������%�����

�� ��

�������������� ������������ � �����������

� �������������

����������

� ������������������������������

���������������������������������

�������������������������������������

������������

�� ��

�������������� ��� ��������� � �����������

�������������

����������������

� �������������� �� ��

������������ ������������������������������������� �� ��

����� �������������

��������������������

������������ ���������������������������

�����������������

�� ��

� �������������������� � ��������������������������������

��������

�� ��

���������

���������

����������

Page 95: 001 Системный Администратор 10 2002

образование

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

Атрибуты: Таблица №1Содержит: Каталог (0-*), ПакетП-

редложений (0-*), Контрагент (0-*),Документ (0-*), Банк (0-*), Склад (0-*).

РасчетныйСчет(BankAccount)Описание: Расчетный счет описы-

вает банковский счет контрагента вобъеме, необходимом для оформле-ния (и передачи) документов.

Атрибуты: Таблица №2Содержит: ДополнительныйРек-

визит (0-*).

Контакт (Contact)Описание: Контакт предназначен

для ответа на вопросы: «Где найти?»и «Кого спросить?».

Содержит список ФИО контактныхлиц (например, список сотрудниковотдела продаж), список телефонов,факсов, адресов электронной почтыконтакта, ICQ.

Атрибуты: Таблица №3Содержит: КонтактноеЛицо (0-*),

Телефон (0-*), Факс (0-*), Почта (0-*), ICQ (0-*).

Пример структуры XML-схемы в формате HTML.

<КоммерческаяИнформация> соби-рательный элемент для всего, что мо-

��� ����������� ����������� �

� �� �����������!����"�#�$� �

�%��

� ��� �����"����%�$�&�

� �� ���������%�$�&�

� �� ��������%�$�&�

� �� ��� �����"�%�$�&�

� �� ��������������&�����%�$�&�

� ���'��

� �� ���#��������%�$�&�

������������

��(� ����������� ����������%��

��������� ��)�*�)+��

��������� ���'��

���$�����'�����������������������,-"��"��������)+��-������������)��������

������������ ��������#���������� �����"��� �����"�����������������&��������������

�����%������ � ������������

��������� �����������������(��

жет быть упомянуто в процессе обме-на.<description> - предназначен для пе-редачи «сопроводительной записки»в виде произвольной текстовой ин-формации по документу.

Представленный стандарт обме-на коммерческой информацией даетвозможность организациям обмени-ваться информацией в одном форма-

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

� �������������������������� �!"#$������!��%&����������'�����&()�(��*�+�,�)�*%(-��-&�,�.�����/��0#12�3����#/�4�!�5��6�7��/����8�/��1/0�9:��!#9/��5�:�������

����#��;)�*%(-��-&�,�<��(-=>������������������#/���2��)�?������*�(-�@��(�+>-(�)���&�,)�*%(-��-&�,A��4#�B#���#�4�!�:���4����C��:��5�4�/��0#�2�B�:�� ���5�5�4��:���B5��0D

#�2�/� �/�5�2��#$��������:��4� 9��#/9E�;)�*%(-��-&�,�;<��(-=>������,����(-=>��������������#/���2�;,�����������������#/��6�#/���-�'%%>(*��FG���H'%%>(*��I�;,���������������. ��4���-�'%%>(*��FG���H'%%>(*��I�;,���������������J�# ���-�'%%>(*��FG���H'%%>(*��I�;,�����������������/���6���-�'%%>(*��FG���H'%%>(*��I�;,���������������A� �/A��4��8�#�2���-�'%%>(*��FG���H'%%>(*��I�;,���������������K� 9��#/���-�'%%>(*��FG���H'%%>(*��I�;,�; ����������,

Page 96: 001 Системный Администратор 10 2002

94

женщина и компьютер

С древних времен отношения меж-ду полами складывались на основаниифизического превосходства. Такие от-ношения остались и сегодня. До сих пор«положено», что мужчина – сильныйпол – занимается тяжелой работой идобыванием еды, а женщина – слабоесоздание – должна рожать детей и дер-жать в порядке дом. Мужчина – силь-ный, а женщина – мудрая. Только се-годня все немного перепуталось: длядобывания еды мужчине не надо боль-ше ходить на охоту, а достаточно весьдень просидеть у экрана монитора, на-жимая кнопочки. И чем эта работа та-кая тяжелая и трудоемкая? Сегоднятакие профессии, как системный адми-нистратор или программист приобрелиметку сугубо мужского способа зара-батывания кучи денег. Сегодня эти спе-циальности очень престижны и высо-кооплачиваемы в России (не совсемтак, глав.ред.), а тем более за рубежом.А почему бы женщине не заняться та-кой простой работой – и мудрость мож-но применить, и физической нагрузкипрактически никакой. Так почему жеженщине так тяжело найти работу вэтих отраслях? Почему даму неохотноберут на работу даже тестером, не го-воря уже о программистах?

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

Резюме выглядели следующим об-разом: я - студентка шестого курсаМГТУ им. Баумана, знания СУБД:Access, MS SQL 7.0, администрирова-ние 1С-Предприятие 7.7; базовые зна-ния бухучета, опыт Web-разработок,знание английского языка. Марина – вэтом году закончила МГТУ с краснымдипломом, имела разовый опыт разра-ботки программы для небольшой фир-мы, знания: Delphi, MS SQL 7.0, базо-вые знания 1С, технический английский+ разговорный, начала изучение C++.

Светлана через свое агентство нашланам несколько серьезных работодате-лей и оформила нас на собеседования.Вакансии были выбраны такие: систем-ный администратор, тестировщик, про-граммист.

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

Первый ответ был больше похож наотмазку: в объявлении говорилось, чтофирма не против взять студента стар-ших курсов технического ВУЗа с базо-выми знаниями MS SQL 7.0/2000. Вфирме же мне сказали, что брать сту-дентку они не намерены, при этом необъясняя конкретной причины. С Мари-ной же была проведена беседа о «лич-ном», где подробно допытывались ин-формации о ее семейном положении.В итоге ответ был весьма суров: «Де-вушку на работу не возьму… Девушкастановится мамой, а программирова-ние – это…», и далее - длинный моно-лог о непрерывности и качественностиинтеллектуального процесса.

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

Для себя с Мариной мы отметилиследующее: в этих фирмах никто не по-интересовался нашим уровнем профес-сионализма.

Еще скажу пару слов о размерахзаработной платы: у женщин оплататруда, в основном, все-таки ниже, чему мужчин. По данным все того же кад-рового агентства, средний уровень за-работной платы для мужчины-програм-миста Oracle составляет $600 - $800 вмесяц (в отдельных местах, до $1200),а женщинам платят всего $200 - $400.Причем, малейшая профессиональнаяошибка, допущенная женщиной-про-граммистом, рассматривается коллега-ми с пристальным вниманием.

Наша собственная статистика тако-ва: из 16 фирм, в которые были направ-лены наши резюме, только восемь неостались без ответа (учитывая, что кад-ровое агентство уже проводило первич-ное собеседование), а из восьми ока-залось 6 отказов.

Так что же теперь? Неужели нам,женщинам, так и не суждено найти ра-боту по специальности? Напротив!Женщина своего добьется! В различ-ного рода компаниях, занимающихсяразработками бухгалтерского про-граммного обеспечения, в торговыхцентрах, в банках, да и во многих дру-гих местах успешно работают женщи-ны: WEB-дизайнеры, системные адми-нистраторы, координаторы техническо-го отдела, системные аналитики, да ипрограммисты-разработчики тоже. Не-смотря ни на что, самые настойчивыеи упрямые все-таки умудряются добить-ся потрясающих результатов. И мы сМариной тоже добились-таки того, кчему стремились! Она стала работатьв одной из ведущих компаний по раз-работке программного обеспечения длякомпаний сотовой связи, я же устрои-лась системным администратором вторговый центр. Так что вывод один:при правильном подходе выживет силь-нейший — будь это мужчина или жен-щина, надо только быть настойчивым!

Евгения Саблина

Уступитеместоженщине!

Page 97: 001 Системный Администратор 10 2002

95№1, октябрь 2002

женщина и компьютер

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

так или подобным об-

разом отвечают молодые люди в воз-расте 22-28 лет на вопрос о причинах,побудивших их к поиску работы в ком-пьютерной компании. Основной составперсонала бурно развивающихся ком-пьютерных фирм – именно такие моло-дые ребята, со свежими мозгами, оп-тимизмом и желанием преобразоватьокружающий мир. Есть, правда, однаособенность: женщин в такие компанииберут на работу достаточно неохотно.Анализ состава компаний говорит отом, что компьютерный бизнес преиму-щественно мужской. И причин для это-го достаточно много. Прежде всего,различна мотивация. Для мужчин важ-но достижение поставленной цели, они,собственно, для этого и предназначе-ны – преобразовывать окружающиймир. Для женщин же характерно жела-ние сохранения жизни. И довольно ча-сто представительницы прекрасногопола идут на работу в такие компаниине от хорошей жизни. Медицинская ста-тистика, в свою очередь, показывает,что, как бы компьютеры не были совер-шенны, они больше предназначены длямужчин, чем для женщин. В психологи-ческом плане, компьютерный бизнеспредполагает больше работу в систе-ме «человек – знак» и требует именнологического мышления - правополу-шарного. Женщинам же больше свой-ственно эмоциональное мышление - ле-вополушарное. Даже гормональный со-став у мужчин и женщин сильно отли-чается. Если сравнить количественный

состав гормонов чувства и гормоновдействия у мужчин и женщин, то карти-на будет выглядеть примерно так: наодну часть гормонов чувства у мужчинприходится около тысячи частей гормо-нов действия, а у женщин – с точнос-тью до наоборот: на одну часть гормо-нов действия приходится в тысячу разбольше гормонов чувства. Получается,что основная деятельность женщин –чувства, а основная деятельность муж-чин – действие. И когда мужчина начи-нает много чувствовать, а женщина –много действовать, нарушается гормо-нальный баланс в организме. Ничегохорошего из этого, как Вы сами пони-маете, выйти не может. Да и при рас-смотрении ситуации взаимоотношенийв группе видно различное отношениеженского коллектива к мужчинам, при-сутствующих в нем, или мужского – к1-2 женщинам в том же положении.Если женщины в такой ситуации будутчувствовать себя комфортно, то муж-чины просто заработают невроз, пото-му что женщине важно отношение кней, а мужчине – отношение к тому, чтоон делает.

Специфика работы в компьютернойфирме такова, что часто персоналу при-ходится работать в стрессовой ситуа-ции (например, сдача проекта, которыйпо каким - либо причинам «не идёт»). Авосприятие стресса у мужчин и женщинразлично - мозг реагирует по-разному.У женщин в момент опасности, пустьдаже гипотетической, в работу включа-ются все мозговые центры и отключа-ются только после того, как опасностьперестаёт существовать. У мужчин вмомент опасности включается толькоодин конкретный мозговой центр, дея-тельность которого через 7-10 минутугасает, если опасность не подтверж-дена другими центрами, отвечающимиза реагирование на конкретный видраздражителя. И получается, что муж-чины при возникновении стрессовой си-

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

Ещё одна особенность таких фирмв том, что по роду деятельности про-граммистам часто приходится рабо-тать вдвоём, в «тандеме». И от взаи-моотношений друг с другом часто за-висит результат такой работы. Здесьтоже есть несколько моментов. Приработе в паре один из специалистовстановится ведущим, другой – ведо-мым. При этом роли часто меняются.Мужская психика довольно спокойнореагирует на смену ролей, так какдело важнее. А вот женская – нет.Выше я уже писал, что для женщиныважно отношение к ней. И по этой при-чине смена ролей для женщины невсегда происходит безболезненно.Часто эти перемены роли восприни-маются как покушение на безопас-ность, что, соответственно, можетвызвать совершенно непредсказуе-мую реакцию. По этой причине не-большие компании, состоящие из 5-7человек, являются достаточно замк-нутыми сообществами мужчин, а вкрупных компьютерных компанияхженщины занимают должности, свя-занные с административной работой.

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

Вячеслав Михалёв,психолог.

Почему их мало

в компьютерныхкомпаниях

Page 98: 001 Системный Администратор 10 2002

96

анонс

Тема номера

Интервью с начальником«Управления Р»Александром СлуцкимБыл уже восьмой час вечера. В

кабинете начальника отдела по борь-бе с компьютерными преступлениямиАлександра Слуцкого обсуждалисьдетали завтрашнего «оперативногомероприятия». Собирались брать ма-терого хакера. Когда детали завтраш-него рейда намеченного между про-чим на 6 утра были согласованы,Александр Сергеевич извинился, до-стал из сумки котлету и начал усталоее поглощать. «Вы меня извините, яеще не завтракал». Собственно я исам уже понял, что работа самого ин-теллектуального «хакерского» отделане сахар.

Создание простейшейстатистики для InternetService ProvidersВ большенстве случаев, при со-

здании ISP, самым главным вопро-сом становится — построение на пер-вых порах простейшего биллинга:подсчет количества времени и денег,затраченных пользователем вInternet’e.

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

Cравнение сетевыхсканеров безопасностиСканер безопасности - это про-

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

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

Основными пользователями сис-тем аудита безопасности являютсяпрофессионалы: сетевые админист-раторы, специалисты по безопаснос-ти и т.д. Простые пользователи тожемогут использовать сканеры, но ин-формация, выдаваемая такими про-граммами, как правило специфична,что ограничивает возможности ее ис-пользования неподготовленным чело-веком.

МЫТАРСТВАБЛАЖЕННОГОСИСАДМИНАБольшинство системных админи-

страторов не выбирают эту карьеру,она предназначена им судьбой.Меня судьба взяла за шкирку и по-садила в сисадминское кресло со-вершенно случайно. Я работал про-граммистом в одной государствен-ной конторе и однажды имел несча-стье попасться на глаза шефа в несовсем трезвом состоянии. Делобыло в 10 часов утра — самое, чтони на есть, рабочее время. Есте-ственно, на следующий день менявызвали на ковер и заявили, чтобыть мне отныне... ни за что не по-верите — «системным администра-тором»!

Продолжение статьипро механизм отраженийв Java.«Я постараюсь рассказать о са-

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

Б Е З О П А С Н О С Т Ь

ЧИТАЙТЕВ СЛЕДУЮЩЕМНОМЕРЕ:

ЧИТАЙТЕВ СЛЕДУЮЩЕМНОМЕРЕ:

№1, Октябрь, 2002 год

УЧЕРЕДИТЕЛИВладимир ПоложевецАлександр Михалев

РУКОВОДИТЕЛЬ ПРОЕКТАПетр Положевец

РЕДАКЦИЯГлавный редакторАлександр Михалев[email protected]Ответственный секретарьНаталья Хвостова[email protected]

ХудожникИгорь Усков[email protected]ВерсткаВладимир Положевец[email protected]Владимир Лукин[email protected]

РЕКЛАМНАЯ СЛУЖБАтел./факс:(095) 298-0316Наталья Хохловател.:(095) 928-8253 (доб. 112)Наталья Политыко[email protected]

103012, г. Москва, Ветошныйпереулок, дом 13/15тел.: (095) 928-8253 (доб. 112)факс: (095) 928-8253Е-mail: [email protected]: www.samag.ru

ИЗДАТЕЛЬЗАО «Редакция «Учительскойгазеты»

Отпечатано ЗАО «Холдинговаякомпания «Блиц-информ».Образцовая типография «Блиц-принт» г. Киев, ул. Довженко, 3Тираж 5000 экз.

Журнал зарегистрированВ Министерстве РФ по делам пе-чати, телерадиовещания исредств массовых коммуникаций(свидетельство ПИ № 77-12542от 24 апреля 2002 г.)