Новости :

Основы совместного доступа в интернет для нескольких ПК

Основы совместного доступа в интернет для нескольких ПК

В интернете существует масса материалов, посвященных распределению (sharing) доступа к интернету. Но, к сожалению, большинство из них или слишком простые, или слишком мудреные. В этой статье я постараюсь максимально приемлемо изложить все, что нужно для построения локальной сети (LAN) дома и для распределения соединения с интернетом между компьютерами. Чтобы мне не раздувать материал, я рассмотрю вариант организации сети только под Windows. Если вас интересуют другие операционные системы - напишите мне, сделаем статью и про них тоже. Хотя, большинство вопросов по организации домашней сети бывает именно про Windows, поэтому на ней мы и фокусируем наше внимание.

Построение локальной сети

Первое что мы сделаем с вашими компьютерами с Windows, это убедимся, все ли они имеют сетевые Ethernet карты и установлен ли на них протокол TCP/IP. Многие игры используют протокол SPX/IPX, лучше деинсталлируйте все протоколы с вашей машины кроме TCP/IP. Установка и удаление протоколов производится через щелчок правой клавишей мыши по значку "Сетевое окружение" (Network Neighborhood) или "Моя сеть" (My Network Places). Далее перейдите в свойства (properties), а потом нажмите правой клавишей на ваше соединение и там тоже выберите свойства. Сейчас вы сможете управлять соединением.

Следующий вопрос, который нам необходимо решить: будете ли вы использовать прямое соединение с вашим компьютером или станете использовать маршрутизатор вкупе с брандмауэром (firewall) для принятия соединения и перенаправления его на ваши компьютеры? Это решение достаточно ответственно, поэтому, если у вас есть деньги, лучше приобретите маршрутизатор. Существует несколько причин, почему использование выделенного маршрутизатора лучше чем использование вашего компьютера для той же цели. Первой причиной является безопасность. Большинство хороших маршрутизаторов (лично я рекомендую Netgear RT314) уже содержат средства фильтрации пакетов, что делает выход вашей сети в интернет безопаснее (естественно, при должной настройке). Конечно, такое устройство только с натяжкой можно назвать брандмауэром/firewall, но его возможности будут дополнять программный брандмауэр/firewall.

Мы рекомендуем вам использовать следующие брандмауэры:

При должной конфигурации, маршрутизатор вполне подходит для усиления безопасности компьютеров, которые он отделяет от интернета. Вторая причина состоит в том, что выделенный маршрутизатор производительнее чем программный на компьютере. Хотя многие будут с этим спорить: вроде как маршрутизация пакетов на компьютере отнимает не слишком много производительности. Но лучше иметь компьютер полностью в своем распоряжении, нежели отдавать даже часть производительности на интернет. И третья причина использования маршрутизатора - это надежность. Когда после покупки маршрутизатора я форматировал жесткий диск своего компьютера, я легко смог подключиться к интернету с другой машины. Вы можете делать, что хотите с вашими компьютерами, при этом на соединение с интернетом это никак не повлияет. Всем процессом связи занимается маршрутизатор. Если бы вы использовали компьютер в качестве шлюза в интернет, и он бы повис, в то время как ваш товарищ скачивал бы 650 Мбайт имидж диска, я бы послушал его слова в этот момент.

Следующее, что нужно определить: использовать концентратор (hub) или нет. Некоторые говорят: "Почему это я должен использовать какой-то концентратор, если я соединяю две системы друг с другом одним кабелем, и все прекрасно работает?" Хорошо. Во-первых, ваша связь не такая быстрая, какой могла бы быть. Вам придется использовать перекрещенный кабель, который не так хорош с точки зрения скорости и надежности, как обычный CAT 5 кабель плюс концентратор. Во-вторых, при использовании концентратора вы без труда добавите еще некоторое количество компьютеров к вашей сети. А при прямом кабельном соединении вы столкнетесь с проблемами. Поэтому мне больше нравится использовать концентратор даже при соединении всего двух компьютеров. Цены на концентраторы сейчас настолько низки, что на них уже можно не обращать внимание. Также следует отдельно отметить, что лучше покупать даже не концентратор, а коммутатор (switch). Коммутатор намного лучше концентратора, так как он может обрабатывать несколько потоков данных одновременно и может перенаправлять сетевой трафик в зависимости от MAC адреса получателя. Предположим, у нас есть три компьютера. Если первый компьютер общается с третьим, то второй компьютер не сможет передать много трафика. Пакеты на второй компьютер будут передаваться в промежутках между общением 1-го и 3-го. Поэтому, если у вас есть выбор между концентратором и коммутатором, выбирайте второе. Он стоит немного больше, но, поверьте, он того стоит.

Хорошо, предположим, что у вас установлено два компьютера с Windows и протокол TCP/IP. Сейчас необходимо сделать несколько шагов, которые позволят компьютерам увидеть друг друга в сети. Пропуск хотя бы одного шага приведет к неработоспособности сети. Во-первых, убедитесь, что IP адреса компьютеров принадлежат одной подсети. Я обычно использую подсеть 192.168.0.x. Вы можете использовать IP-адрес 192.168.0.10 для первого компьютера, и 192.168.0.20 для второго, маска подсети для них будет 255.255.255.0. Объяснение масок подсетей и адресации TCP/IP выходит за рамки нашей статьи, но вы можете найти интересующую вас информацию сами (посмотрите список литературы в конце статьи). Во-вторых, необходимо убедиться, что обе машины принадлежат одной и той же рабочей группе. Для этого нажмите правой клавишей мыши на "Сетевое окружение", выберите свойства и перейдите на закладку "Идентификация". Назовите свою рабочую группу как-нибудь покруче, но без всяких "левых" символов и не слишком длинно. Далее, назовите ваши компьютеры как-нибудь осмысленно. Эти имена вы будете использовать для связи по сети. После того, как вы все это сделаете, попытайтесь выполнить ping на компьютеры с помощью IP адресов, чтобы удостовериться в работоспособности сети. Следующий шаг не является обязательным, но он весьма полезен. Нажмите клавишу "Пуск" и попробуйте поискать на жестком диске файл hosts. Вы найдете его в каталоге /drivers/etc, и, скорее всего, он будет называться hosts.sam. Откройте его с помощью Блокнота (Notepad) и добавьте в него имена ваших компьютеров и их IP адреса, как показано в примере в этом же файле. (Данная операция имеет смысл только при присвоении статических адресов вашим компьютерам. Но это все равно не помешает запуску DHCP, если вы будете его использовать, так что не беспокойтесь). Сохраните измененный файл без расширения (то есть уберите .sam). Сейчас у вас есть файл узлов, который будет использоваться для разрешения имен совместно с DNS сервером. Вы можете произвести ping на свои любимые сайты, получить их IP адрес и добавить его под каким-нибудь коротким именем в файл hosts. После этого вы сможете обращаться к сайту по этому имени. Но самое важное: вы сейчас можете производить ping компьютеров в локальной сети по имени, а не по IP адресу. Сейчас произведите ping машин по тем именам, которые вы ввели в файл.

Отлично, вы установили сеть. Пришло время настроить соединение с интернетом.

Среди вас будут и те, кто не приобрел маршрутизатор по каким-либо причинам. Я сам был таким же некоторое время и решал свои проблемы с помощью Windows Internet Connection Sharing, ICS ("Общий доступ к подключению интернета" в русской версии, прим. переводчика). Самое главное, что здесь следует запомнить: одна из машин выделяется под соединение, и если ее выключить, все остальные компьютеры останутся без интернета. На самом деле, ICS является разновидностью NAT (Network Address Translation, перевод сетевых адресов), в том смысле, что она использует компьютер для раздачи динамических адресов другим машинам подобно DHCP серверу. Узловой компьютер, который осуществляет связь с интернетом, имеет настоящий IP адрес, а все остальные машины получают "левый" IP адрес. По умолчанию MS использует для ICS подсеть 192.168.0.x, где 192.168.0.1 является узловым компьютерам, а все остальные адреса подсети раздаются другим машинам. В общем, после установки ICS на ваш компьютер, подключенный к интернету, его сетевой карте будет присвоен адрес 192.168.0.1, а всем остальным компьютерам в сети нужно будет указать на получение своих адресов с DHCP ("получать адрес автоматически" в свойствах TCP/IP, прим. переводчика).

Windows ICS входит в состав Windows 98, Windows ME и Windows 2000. Она также будет поставляться и с будущей версией Windows XP.

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

Используем маршрутизатор

Хотя ICS и может разделять соединение с интернетом на другие компьютеры, по указанным выше причинам это не лучший метод. По возможности, следует купить и настроить домашний маршрутизатор для разделения соединения с интернетом. Как было сказано выше, мы рекомендуем использовать Netgear RT314. У него есть свой форум поддержки на dslreports.com, и довольно обширное общество энтузиастов, которые могут вам настроить устройство для максимальной безопасности и производительности.

RT314 (мы будем использовать эту модель для примера, хотя и Lynksys тоже очень на него похож) имеет два интерфейса управления, Telnet и Web, но также может использовать и соединение по COM порту, если у вас есть кабель и вам это нужно. Мы предпочитаем использовать Telnet для управления, а Web использовать только для первоначальной настройки. После приобретения маршрутизатора, вы легко выполните физическую установку и подключите его к вашему широкополосному (broadband) подключению (в России это, как правило, или выделенная линия, или ISDN. Прим. переводчика). Большинство маршрутизаторов не поддерживают доступ по коммутируемой линии (dial-up). Далее следует получить информацию о соединении от вашего провайдера и ввести ее через Web-интерфейс маршрутизатора по адресу http://routersdefaultaddress, скорее всего это 192.168.0.1 или 192.168.1.1. После этого выполните соединение через Telnet с вашим маршрутизатором и произведите необходимую настройку. Большинство настроек относятся к усилению безопасности и производятся через модификацию фильтров брандмауэра/firewall.

Очень полезно будет сделать DNS запись для вашего маршрутизатора в файле hosts. Выберите крутое имя и добавьте в файл hosts строку следующего вида:


192.168.0.1 Fw

Таким образом, когда вы набираете fw в строке адреса вашего браузера, вы попадаете на Web-интерфейс маршрутизатора. Также вы сможете в командной строке набрать "telnet fw" и, установив telnet соединение, вы получите запрос на ввод пароля. Ну, или вы сможете проверить доступность маршрутизатора, выполнив "ping fw". Сейчас давайте обсудим некоторые вопросы, связанные с безопасностью. Вы набираете 192.168.x.x изнутри вашей сетки, и попадаете на Web-интерфейс маршрутизатора. Но если вы попытаетесь сделать то же самое снаружи, вы никуда не попадете. Этот IP адрес является "левым" и он присваивается внутреннему интерфейсу маршрутизатора. Когда вы попытаетесь получить доступ к маршрутизатору, вы его не получите. Уже введенные по умолчанию фильтры блокируют web, telnet и ftp порты по умолчанию. Это очень хорошо: вы же не хотите, чтобы весь интернет ломился к интерфейсу управления вашего маршрутизатора, даже если у вас там длинный пароль? Да, и обязательно поменяйте свой пароль. В следующей статье, мы, возможно, более детально рассмотрим этот вопрос. Но общеизвестно, что очень многие хакеры проникает в системы через пустые, или принятые по умолчанию пароли. Убедитесь, что вы поменяли пароль прежде чем выходить в интернет.

Осталось только определить диапазон адресов для раздачи по локальной сети через DHCP, (я рекомендую это сделать, тогда любой человек может прийти к вам в гости и легко подключиться к интернету) и сконфигурировать клиентские компьютеры, чтобы они использовали маршрутизатор для выхода в интернет. Убедитесь что в качестве шлюза по умолчанию у компьютеров выставлен внутренний интерфейс маршрутизатора (то есть 192.168.0.1) и указан DNS сервер. Вы можете настроить клиентские компьютеры использовать DNS провайдера, или вы можете указать на маршрутизатор для разрешения адресов DNS, поскольку маршрутизатор сам может выступать в роли DNS сервера (кэширующего, прим. переводчика). А если вы используете DHCP, то вы можете сказать ему раздавать адрес DNS сервера (и адрес шлюза по умолчанию тоже, прим. переводчика) клиентам и не заботиться больше о ручном прописывании. Кстати, я использую статические адреса для клиентов, поэтому я добавляю их имена в hosts файл, как описано выше. Но я также использую и DHCP сервер на случай, если кто-нибудь притащит свой компьютер поиграться.

Итак, вы уже все установили, осталось произвести только окончательные настройки. Вы можете посмотреть сетевую статистику на маршрутизаторе через Telnet или Web-интерфейс. Да, там вы сможете оценить, насколько быстр RT314. На самом деле он является не только маршрутизатором, но еще и коммутатором. Вы можете играться, скачивать файлы и читать почту в одно и то же время, и вы никогда не увидите перегрузки (коллизии). Я никогда еще не наблюдал ее на своей сети. Под окончательными настройками я подразумеваю скачивание улучшенных фильтров и прошивок маршрутизатора. Все это можно получить на www.dslreports.com, и там же вы сможете завести персональную учетную запись. Все это бесплатно, и этот сайт великолепен с точки зрения поддержки маршрутизатора, поэтому я его вам и рекомендую. Там вы сможете просмотреть форумы и найти форум, посвященный Netgear. Посмотрите ответ на ваш вопрос в предыдущих сообщениях, прежде чем его задавать. Скорее всего, кто-то уже решал возникшую у вас проблему. Прошивки маршрутизатора также можно скачать на этом сайте.

От переводчика: В качестве главного сервера я рекомендую использовать Windows 2000 Server. Там вы легко сможете настроить DHCP и DNS (и не придется прописывать файл hosts). Все это не так сложно как кажется. Если возникают вопросы: купите книжку из списка литературы. Если вы не будете использовать внешнего маршрутизатора, установка Windows 2000 все равно предпочтительнее, так как там можно использовать различные фильтры пакетов. А Windows 98/Me лучше в интернет вообще не выставлять, это система не для работы, а для игрушек. IMHO.

Источник: www.3dnews.ru

Комментарии: (0) | Интернет и Сети | 2006-06-05

Настройка VPN(PPTP)-сервера под Linux

Настройка VPN(PPTP)-сервера под Linux

Дмитрий Коптев (dimez@nm.ru), "Настройка VPN(PPTP)-сервера под Linux" - 22/04/2003 || Библиотека ЛинуксЦентра

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

Комментарии: (0) | Linux | 2006-06-05

Apache как прокси-сервер

Apache как прокси-сервер

Валентин Синицын (val AT linuxcenter DOT ru), "Apache как прокси-сервер" - 04/05/2006 || Библиотека ЛинуксЦентра

Рассмотрим типичную для небольшой организации конструкцию: шлюз в Интернет, работающий под управлением Unix или Microsoft Windows, прокси-сервер, web-сервер сети Интранет, почтовый сервер и т.д. Оказывается, число ее элементов можно несколько сократить, и в соответствии с золотым правилом инженера, увеличить тем самым общую надежность системы. Сегодня мы поговорим о делегировании Apache основных функций кэширующего прокси-сервера (например, Squid) и даже кое-чего сверх них. В качестве базовой ОС будем использовать Linux, хотя многое из сказанного ниже может быть без ограничения общности применено и для других платформ.

Согласен, использование Apache в качестве прокси-сервера выглядит несколько нестандартно, однако, оно имеет ряд преимуществ. Это, в первую очередь, возможность динамического сжатия документов, отправляемых клиентам, что может вылиться в серьезную экономию, если для передачи данных используется арендованный канал с помегабайтной оплатой входящего трафика (допустим, офисов у фирмы два, а сервер всего один). Кроме того, оно сокращает число сервисов, работающих в системе, а значит, у потенциального злоумышленника будет меньше мишеней для проведения атаки, а у администратора, в свою очередь, меньше объектов, требующих неусыпного наблюдения и поддержки. Впрочем, как и все в нашем неидеальном мире, Apache в роли прокси-сервера имеет и некоторые недостатки, как-то: содержит экспериментальные или написанные сторонними разработчиками модули (при желании можно обойтись и без них) и неизвестным образом ведет себя при увеличении нагрузки (вполне допускаю, что все будет прекрасно работать, однако, специализированного стресс-тестирования не проводил). Какая чаша перевесит – решать вам. Руководствуясь личным опытом, я вполне могу рекомендовать применение прокси-сервера на базе Apache в небольших сетях.

Покончив с теоретическими вопросами, перейдем к техническим деталям. Для реализации задуманного нам понадобится Apache версии 2.0.53 и выше (более ранние версии имеют ошибки в mod_cache, препятствующие нормальной работе с кэшированными документами) с включенными mod_proxy, mod_cache и mod_deflate. В отличие от специализированных решений вроде упомянутого выше Squid, прокси-сервер на базе Apache имеет существенно модульную архитектуру, все мыслимые и немыслимые функции которой построены по принципу: общая база + провайдеры. Мы не раз убедимся в этом по ходу изложения. Итак, приступим к первой фазе:

Запуск прокси-сервера

Для того, чтобы Apache мог принимать и обрабатывать прокси-запросы, необходимо загрузить модуль mod_proxy, входящий в стандартный комплект поставки и прекрасно документированный. Здесь и далее в этой статье мы не будем дублировать страницы руководства, останавливаясь лишь на нетривиальных моментах. mod_proxy, как и большая часть других упомянутых в статье модулей, обычно не собирается в стандартной конфигурации Apache, поэтому вам, вероятно, придется заново скомпилировать сервер, указав соответствующие параметры сценарию configure. За поддержку mod_proxy отвечает опция «--enable-proxy», прочие же параметры я буду приводить в тексте в скобках после имени соответствующего модуля.

В соответствии с представленной выше формулой, mod_proxy образует фундамент, на котором работает система поддержки прокси-запросов. Их реализации, специфичные для различных протоколов, вынесены в отдельные модули: mod_proxy_http (--enable-proxy-http), mod_proxy_ftp (--enable-proxy-ftp) и mod_proxy_connect (--enable-proxy-connect). Последний из них необходим для работы с запросами HTTP CONNECT, в частности, защищенными SSL-соединениями.

Прежде чем говорить о настройке mod_proxy, сделаем пару замечаний. Первое: Apache поддерживает два типа прокси-серверов: прямые (forwarding proxy) и обратные (reverse proxy). Нас будут интересовать исключительно прямые прокси-сервера. Обратные прокси применяются для балансировки нагрузки и не имеют ничего общего с темой данной статьи. Второе: прокси-запрос не является для Apache чем-то чужеродным. Заглянув в исходные тексты сервера, вы обнаружите, что все клиентские запросы, независимо от того, кому они адресованы, описываются одной и той же структурой. Apache помечает запросы, предназначенные другим серверам, специальным флагом, но не более того. Из этого, к примеру, следует, что в параметрах модуля mod_proxy отсутствует директива для указания порта, который следует использовать для приема входящих соединений (сноска: напомним, что согласно общепринятым соглашениям для этих целей используется порт 3128). Apache способен принимать и обрабатывать прокси-запросы на любом порту, который разрешен к “прослушиванию” директивой Listen. Впрочем, на практике зачастую оказывается удобнее провести границу между локальными и переадресуемыми запросами. Для достижения этой цели можно создать специальный виртуальный хост, например, на порту 3128, пользуясь директивой VirtualHost. Подробности ищите в документации к Apache. Дальнейшее изложение неявно предполагает, что вы уже настроили виртуальный хост и размещаете предлагаемые директивы внутри принадлежащей ему секции httpd.conf (Подсказка для самых нетерпеливых: в конце статьи приведен завершенный фрагмент конфигурационного файла, практически пригодный для вставки по методу Ctrl-C – Ctrl-V)

Чтобы Apache мог принимать прокси-запросы, необходимо явным образом разрешить их, используя директиву “ProxyRequests On”. Однако, не спешите этого делать, не позаботившись о безопасности сетевых соединений! Оплачивать мегабайты, загруженные предприимчивыми подростками с ProxyHunter'ом в руках – не самое приятное времяпровождение. Параметры доступа к серверу задаются в секции <Proxy> и, в частности, могут иметь следующий вид:

<Proxy *> # Для всех прокси-запросов

Order deny,allow # Сперва запретить, потом разрешить

Deny from All # Запретить всем

Allow from 192.168.0.1/24 # Разрешить доступ из внутренней сети организации

</Proxy>

Здесь реализована простейшая схема контроля доступа, базирующаяся на IP-адресах клиентов. Во многих случаях ее будет достаточно. Но что делать, если вы хотите разрешить использование сервера с компьютеров, не имеющих фиксированного IP-адреса (например, домашних машин особо приближенных сотрудников, которые не прочь получить “городской прокси”)? Для этих целей можно применить авторизацию по имени пользователя и паролю. Поскольку директивы контроля доступа, заключенные между тегами <Proxy> и </Proxy> на самом деле обрабатываются теми же самыми модулями, что следят за «неприкосновенностью» локальных каталогов сервера (ну, не говорил ли я вам, что Apache практически не отличает прокси-запрос от обычного?), вы можете использовать привычную конструкцию:

<Proxy *> # Для всех прокси-запросов

AuthName “Tresspassers” # «Посторонним в.»

AuthFile /some/secret/file # Имя файла, содержащего реквизиты пользователей

AuthType Basic # Метод авторизации - базовый

Require valid-user # Пропускать всех, кто перечислен в /some/secret/file

</Proxy>

Естественно, предварительно следует создать файл /some/secret/file при помощи утилиты htpasswd(1) и загрузить соответствующие модули (mod_access и/или mod_auth). При необходимости оба метода можно комбинировать. При этом бывает полезно пользоваться директивой “Satisfy All|Any”, указывающей, требовать ли от потенциального клиента соответствия всем условиям (применительно к нашей задаче это означает «иметь разрешенный IP-адрес и ввести правильное имя пользователя/пароль») или лишь одному из них. Последний вариант наиболее интересен с практической точки зрения, поскольку позволяет избежать раздражающей процедуры ввода пароля для пользователей внутренней сети организации.

Внеся необходимые изменения в httpd.conf, не забудьте перезапустить Apache. После этого откройте свой любимый браузер и удостоверьтесь, что настройки безопасности действуют именно так, как вы задумали.

Кэширование

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

Кэшированием данных в Apache заведует модуль mod_cache (--enable-cache). Именно он принимает решение о том, допустимо ли локальное сохранение того или иного объекта. Непосредственной записью данных на носители занимаются модули-”провайдеры”, из которых нас в первую очередь будет интересовать mod_disk_cache (--enable-disk-cache), реализующий хранение кэша на жестком диске.

Отметим, что в Apache 2.0 оба этих модуля (mod_cache и mod_disk_cache) имеют статус экспериментальных. Ситуация обещает измениться в Apache 2.1, который пока что пребывает в состоянии альфа-версии.

Чтобы включить кэширование, используйте директиву “CacheEnable disk /”, где “disk” - идентификатор модуля-провайдера. Местоположение дискового кэша и его желаемый объем (в килобайтах) задается соответственно директивами “CacheRoot <имя каталога>” и «CacheSize <NNN>», относящимися уже не к mod_cache, а mod_disk_cache. Apache предпринимает меры к тому, чтобы конфиденциальные данные никогда не попадали в кэш сервера, однако, лишняя безопасность все же не повредит. Я рекомендую сделать каталог, в котором хранится кэш, недоступным ни для кого, кроме Apache.

# chown apache:apache /path/to/cache

# chmod 0700 /path/to/cache

Естественно, если в вашей системе Apache работает от имени другого пользователя, имя и группу владельца каталога также следует изменить соответствующим образом.

В целях повышения производительности дисковый кэш имеет многоуровневую структуру. Глубиной вложенности подкаталогов и максимальной длиной их имени управляют директивы CacheDirLevels и CacheDirLength. По умолчанию для них используются следующие значения: CacheDirLevels 2, CacheDirLength 3

К сожалению, Apache 2.0 не имеет никаких штатных средств для управления содержимым кэша. Вы не можете постепенно удалять старые данные или делать это при превышении кэшем некоторой дисковой квоты. Часть из этих проблем решена в Apache 2.1 при помощи специальной утилиты htcacheclean, которая очищает кэш по мере необходимости. Мне не известно, перенесена ли она в ветвь 2.0, однако, в качестве некоторой замены, вы можете написать сценарий, периодически очищающий каталог (и, для верности, перезапускающий Apache), самостоятельно.

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

На данном этапе мы завершили все работы, необходимые для получения “идентичного натуральному ароматизатора” Squid, а точнее, того подмножества его функций, которое используется в типичной малой сети. Теперь мы пойдем несколько дальше и реализуем нечто новое – прозрачное сжатие web-страниц.

Сжатие

Модуль для сжатия HTTP-документов известен каждому уважающему себя web-мастеру. Называется он mod_deflate (--enable-deflate), и, к вящей радости замученного бесконечными сборками из исходных текстов читателя, обычно включен даже в стандартной конфигурации. Его основное предназначение – сжимать локальные HMTL-страницы перед отправкой их пользователю, но, коль скоро Apache “близорук” и не делает особых различий между обычным и переадресованным запросом, он вполне годится и для последних.

После своей загрузки mod_deflate создает фильтр “DEFLATE”, который может быть установлен стандартным образом, например, при помощи директивы “SetOutputFilter DEFLATE”. Руководство к модулю рекомендует поостеречься и отключить сжатие данных для браузеров, которые, несмотря на заявленную функциональность (сноска: Отметим, что отсечение клиентов, не поддерживающих сжатие данных, mod_deflate производит сам, безо всякого участия администратора) не могут обеспечить должный уровень поддержки (например, Netscape Navigator 4.x может корректно обрабатывать только сжатые данные типа text/html, а его версии 4.06-4.08 не способны даже на это), однако, применительно к прокси-серверу это имеет смысл лишь в том случае, когда такие “динозавры” до сих пор имеют хождение в вашей организации. Из других директив, поддерживаемых mod_deflate, следует упомянуть DeflateCompressionLevel,

устанавливающую степень сжатия данных (число от 0 до 9). Большее значение этой величины обеспечивает меньший размер результирующих файлов, но повышает нагрузку на процессор. Для среднестатистической системы оптимальным выбором считается 6. Вы можете не использовать эту директиву, тогда будут иметь место значения по умолчанию, принятые при сборке системной библиотеки Zlib.

mod_filter

Казалось бы, все хорошо. Наш Apache теперь умеет обрабатывать прокси-запросы, хранить их в кэше и даже сжимать перед отправкой. Однако, спустя некоторое (обычно – весьма непродолжительное) время обнаруживаются странные артефакты. Архивы почему-то оказываются упакованными дважды, что пугает неподготовленных пользователей. И тут же возникают два вековечных русских вопроса: “Кто виноват?” и “Что делать?”

Благо, за ответом на первый из них далеко ходить не надо. Как наверняка уже догадался проницательный читатель, проблема кроется в излишней «жадности» нашего mod_deflate, который сжимает все и вся, тогда как браузер готов распаковать лишь вполне определенные типы файлов: текст, HTML-страницы, графические изображения... Лежащее на поверхности решение – ограничить список файлов, подлежащих динамическому сжатию, по расширению (кстати, оно очень хорошо описано в документации к mod_deflate), можно отбросить сразу же. Расширение файла далеко не всегда соответствует его содержимому (те же архивы иногда называются как-нибудь вроде http://www.some-tricky-company.ru/download/download.pl?id=1234&uid=5678), кроме того, вариантов, подлежащих фильтрации, оказывается чересчур много (на самом деле, нам проще сказать, что должно сжиматься и выкинуть остальное). Вторая идея – использовать директиву “AddOutputFilterByType DEFLATE <список MIME-типов>” также терпит фиаско, поскольку она принципиально не способна работать с прокси-запросами (это редкое исключение, подтверждающее правило). Да и нужные нам шаблоны, типа “text/*”, не говоря уж о более сложных, ей явно не по зубам. Что же делать?

Решение существует! (Читатели, имеющие за плечами мат-мех или физфак наверняка испытали непроизвольный прилив радостных эмоций). Это специализированный модуль mod_filter, написанный Ником Кью (Nick Kew) и включенный в стандартный комплект поставки Apache 2.1, усеченная версия которого была портирована автором этих строк обратно в 2.0. В данном разделе речь будет вестись именно о ней.

Исходный код модуля доступен по адресу: http://ktf.physics.usu.ru/~val/mod_filter.zip. Чтобы установить его, распакуйте архив во временный каталог на вашем сервере и дайте команду: apxs -c -i -a mod_filter.c.

Основная идея mod_filter состоит в том, чтобы заменить обычный фильтр так называемым “умным” (smart filter). «Умный» фильтр – это некоторая абстрактная конструкция, содержащая условия срабатывания и набор так называемых провайдеров (опять это слово!), которые, в свою очередь, являются обычными фильтрами. В перспективе подобный подход может сократить количество дублирующегося кода, встречающегося практически в каждом модуле и дающего ответ на вопрос: “Должны ли мы обработать эту порцию данных?” Впрочем, сейчас нас будут интересовать сугубо практические аспекты.

Условия срабатывания “умного” фильтра могут использовать самую различную информацию: поля заголовков прямого запроса (req) и ответа на него (resp), значения внутренних переменных Apache, устанавливаемых с помощью mod_setenvif (env), имена обработчиков (handler), а таже тип передаваемых данных (Content-type).

Для создания “умного” фильтра используется директива “FilterDeclare <имя фильтра>”. Подключением отдельных провайдеров управляет директива “FilterProvider <имя фильтра> <имя провайдера> <условие>”. Здесь под именем провайдера подразумевается название “обычного” фильтра, например, DEFLATE. Завершив настройку “умного” фильтра, следует добавить его в «цепочку» командой FilterChain. При обработке поступившего запроса звенья цепочки последовательно просматриваются до тех пор, пока не будет найден фильтр, условие срабатывания которого для данного конкретного запроса окажется истинным. По умолчанию добавление нового “умного фильтра” происходит в конец цепочки, однако, это поведение можно подавить, используя специальные префиксы в директиве FilterChain. Подробности ищите в документации.

Теперь путь решения проблемы становится ясным. Нам необходимо добавить “умный” фильтр “Compressor” (конечно, вы можете использовать другое имя), который будет обрабатывать данные с типом “text/*”. На самом деле, диапазон MIME-типов, подлежащих сжатию, может быть более широким. Я, например, использую следующую конструкцию:

FilterProvider Compressor DEFLATE resp=Content-type $text/

FilterProvider Compressor DEFLATE resp=Content-type $application/xhtml

FilterProvider Compressor DEFLATE resp=Content-type $application/xml

Знак долара «$» в начале каждого условия обозначает операцию поиска по подстроке. Кроме него, доступен поиск по регулярному выражению (обрамляется символами «/»), а также весь спектр арифметических операций сравнения и специальное условие «*», которое всегда истинно. Обратите внимание, что мы используем «resp=Content-type» вместо «Content-type». Между этими двумя вариантами существует тонкое различие. В первом случае MIME-тип определяется по заголовкам, сформированным удаленным сервером, тогда как в последнем сведения поступают из локальной базы MIME-типов. Некоторые сайты, например, репозитарий SourceForge.net, используют для своих файлов двусмысленные имена, что приводит к недопониманию: http://prdownloads.sourceforge.net/project/release-x.y.tar.gz?download на проверку оказывается HTML-страницей, содержащей список доступных зеркал для файла release-x.y.tar.gz, поэтому лучше доверить право определения типа содержимого удаленному серверу. Уж он-то точно знает, что нам отправил.

Заключение

Вот и подошла к концу данная статья. Если вы внимательно и творчески следовали всем перечисленным рекомендациям, то сейчас в вашем распоряжении имеется многофункциональный сервер Apache, который может самостоятельно обрабатывать запросы, переадресовывать их удаленным web-узлам, кэшировать и динамически сжимать передаваемые данные, причем делает все это в рамках одной кодовой базы. Некоторые из описанных в статье функций в настоящий момент имеют статус экспериментальных или являются сторонними разработками. Ситуация изменится с выходом финальной версии Apache 2.1, который будет содержать “штатные“ реализации mod_cache и mod_filter. До тех пор вы, при желании, можете рассматривать предлагаемое решение как перспективное, хотя мой личный опыт показывает, что надежности вышеупомянутых модулей вполне достаточно для решения “бытовых” задач. Попробуйте сами!

Врезка 1. Пример вызова configure, обеспечивающий поддержку всех необходимых модулей

сonfigure \

--enable-proxy –-enable-proxy-http -–enable-proxy-ftp -–enable-proxy-connect\

--enable-cache –enable-disk-cache\

--enable-deflate\

--enable-mods-shared=all

Врезка 2. Фрагмент файла httpd.conf, реализующий описанную в статье систему

...

# Слушать порт 3128

Listen 3128

...

# Загрузить необходимые модули

LoadModule cache_module modules/mod_cache.so

LoadModule disk_cache_module modules/mod_disk_cache.so

...

LoadModule deflate_module modules/mod_deflate.so

...

LoadModule proxy_module modules/mod_proxy.so

LoadModule proxy_connect_module modules/mod_proxy_connect.so

LoadModule proxy_ftp_module modules/mod_proxy_ftp.so

LoadModule proxy_http_module modules/mod_proxy_http.so

...

LoadModule filter_module modules/mod_filter.so

...

# Создать виртуальный хост на порту 3128

NameVirtualHost *:3128

<VirtualHost *:3128>

# Включить поддержку прокси-запросов

ProxyRequests On

<Proxy *>

# Ограничение доступа по IP

Order deny,allow

Deny from all

Allow from 192.168.0.1/24

# или авторизация по имени пользователя и паролю

AuthName "No trespassers"

AuthType Basic

AuthUserFile <файл с реквизитами пользователей>

Require valid-user

# Если обе схемы используются совместно, укажите здесь

# All, чтобы затребовать разрешенный IP-адрес И правильный пароль

# Any, чтобы затребовать разрешенный IP-адрес ИЛИ правильный пароль

Satisfy Any

</Proxy>

# Настройки кэша

CacheEnable disk /

CacheRoot <путь к каталогу кэша>

CacheSize 51200

CacheDirLevels 2

CacheDirLength 3

# «Умный» фильтр для динамического сжатия

FilterDeclare Compressor

FilterProvider Compressor DEFLATE resp=Content-type $text/

FilterProvider Compressor DEFLATE resp=Content-type $application/xhtml

FilterProvider Compressor DEFLATE resp=Content-type $application/xml

FilterChain Compressor

</VirtualHost>


Статья была впервые опубликована в журнале "Системный администратор", апрель 2005

Валентин Синицын (val AT linuxcenter DOT ru), "Apache как прокси-сервер" - 04/05/2006 || Библиотека ЛинуксЦентра
Комментарии: (0) | Интернет и Сети | 2006-06-05

РЕАЛИЗАЦИЯ МНОГОПОТОКОВОГО "АСИНХРОННОГО СЕРВЕРА TCP" И RPC ДЛЯ ОС LINUX

РЕАЛИЗАЦИЯ МНОГОПОТОКОВОГО "АСИНХРОННОГО СЕРВЕРА TCP" И RPC ДЛЯ ОС LINUX

В заметке приводится код многопотокового эхо-сервера , основанного на использовании неблокирующего ввода вывода и конечных автоматов. Каждый поток сервера использует вызов select( ) для того, чтобы определить по какому из соединений можно производить обмен в данный момент времени. Код для процедуры serv_request , выполняемой ведомыми потоками может быть взят из различных источников ( см. [1],[2],[3]). Параметр , передаваемый в процедуру serv_request , явлется дескриптором пассивного сокета , создаваемый ведущим потоком с помощью вызова процедуры getServerSocket( ).
Необходимо отметить, что приведенное решение основано на свойстве Linux эффективно распараллеливать вызов accept( ). В противном случае возникает необходимость в блокировке мьютекса перед вызовом accept( ),
что влечет за собой последовательное выполнение потоками сервера критической части кода, т.е. вызова accept( ). В среде же Red Hat Linux 9 (например) эта предосторожность не нужна и только снижает производительность. Детальное описание Posix Threads API на русском языке может быть найдено в [2].
Приводится также модифицированный код заглушки sample_svc.c (не за- висящий от шаблона sample.x) , позволяюший скомпилировать многопото- ковый сервер RPC в среде LINUX.
/*
*  ServerNBTHR.c
*/
#include <sys/socket.h>

#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>

#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#define NUM_THREADS 512

pthread_mutex_t request_mutex = PTHREAD_MUTEX_INITIALIZER;

void
die(const char *func, int err)
{
        fprintf(stderr,"%s: %s\n",func, strerror(err));
        abort();
}

                                                                                
void
bark(const char *func, int err)
{
        fprintf(stderr,"%s: %s\n",func, strerror(err));
}
/* 
    Описание поцедуры ведущего потока , которая возвращает
дескрипторов пассивного сокета, привязанного к адресу
сервера.
*/
int
getServerSocket(unsigned short int port)
{
        int listenSocket;
        struct sockaddr_in listenSockaddr;
                                                                                
        if((listenSocket=socket(PF_INET,SOCK_STREAM,0))<0)
                die("socket()",errno);
        memset(&listenSockaddr, 0, sizeof(listenSockaddr));
        listenSockaddr.sin_family = PF_INET;
        listenSockaddr.sin_port = htons(port);
        listenSockaddr.sin_addr.s_addr = INADDR_ANY;
                                                                                
         if(bind(listenSocket,(struct sockaddr*)&listenSockaddr,
                                            sizeof(listenSockaddr)) < 0)
                die("bind()",errno);
                                                                                
        if(listen(listenSocket,5)<0)
                die("listen()",errno);
                                                                                
        return listenSocket;
}

/*
    Описание процедуры выполняемой всеми ведомыми потоками
*/


void *
serv_request(void *data)
{
struct connection_cb
{
        int dataSocket;
        char data[256];
        int dataSent;
        int dataToSend;
        int isReading;
        struct connection_cb *next;
};
                                                                                                   
struct connection_cb *connections = NULL;

int listenSocket = (int)data;
       if(fcntl(listenSocket,F_SETFL,O_NONBLOCK)<0)
               die("fcntl()",errno);
       
       while(1)
       {
               fd_set readFdSet;
               fd_set writeFdSet;
               struct connection_cb *currentConn, **currentConnPtr, *tempConn;
               int maxFdNum;

               FD_ZERO(&readFdSet);
               FD_ZERO(&writeFdSet);
             
              /*
                    Добавление дескриптора к множеству readFdSet
              */
               FD_SET(listenSocket,&readFdSet);
               maxFdNum = listenSocket;
               
           for(currentConn = connections;currentConn!=NULL;currentConn =   
                                                           currentConn->next)
       {

               if(currentConn->isReading)
                       FD_SET(currentConn->dataSocket,&readFdSet);
               else
                       FD_SET(currentConn->dataSocket,&writeFdSet);
       maxFdNum = currentConn->dataSocket > maxFdNum ?currentConn-
                                       >dataSocket : maxFdNum; 
       }
          /*
              Получение множества дескрипторов сокетов для обработки
          */           
       if(select(maxFdNum+1,&readFdSet,&writeFdSet,NULL,NULL) < 0)
       {

               if(errno == EINTR)
                       continue;
               die("select()",errno);
       }
               
       currentConnPtr=&connections;
       
       while(*currentConnPtr!=NULL)
       {

          /*
             Проверка принадлежности дескриптора 
             (*currentConnPtr)->dataSocket к множеству readFdSet
           */

       if((*currentConnPtr)->isReading && 
                  FD_ISSET((*currentConnPtr)->dataSocket,&readFdSet))
       {

         int result = recv((*currentConnPtr)->dataSocket, (*currentConnPtr)->data,
                                                         sizeof((*currentConnPtr)->data),0);

       if(result < 0)
       {
       if(errno!=EINTR && errno!=EAGAIN && errno!=EWOULDBLOCK)
       {
               bark("recv()",errno);
               close((*currentConnPtr)->dataSocket);
               tempConn = *currentConnPtr;
               *currentConnPtr = (*currentConnPtr)->next;
               free(tempConn);
               continue;
       }

               }
       else 
         if(result==0)
               {
               close((*currentConnPtr)->dataSocket);
               tempConn = *currentConnPtr;
               *currentConnPtr = (*currentConnPtr)->next;
               free(tempConn);
               continue;
               }
       else
       {
               (*currentConnPtr)->dataToSend = result;
               (*currentConnPtr)->dataSent = 0;
               (*currentConnPtr)->isReading = 0;
         printf("Recieving  as Slave Thread id = '%d' \n",pthread_self());
       }

               }
       else 
         /*
             Проверка принадлежности дескриптора 
             (*currentConnPtr)->dataSocket к множеству writedFdSet
         */
         if(FD_ISSET((*currentConnPtr)->dataSocket,&writeFdSet))
       {
       int result = send((*currentConnPtr)->dataSocket, 
               (*currentConnPtr)->data+(*currentConnPtr)->dataSent,
                (*currentConnPtr) ->dataToSend-(*currentConnPtr)->dataSent, 0);
                       
       if(result < 0)
       {

         if(errno!=EINTR && errno!=EAGAIN)
               {
                       bark("write()",errno);
                       close((*currentConnPtr)->dataSocket);
                       tempConn = *currentConnPtr;
                       *currentConnPtr = (*currentConnPtr)->next;
                       free(tempConn);
                       continue;
               }
                       }
               else
               {
                       (*currentConnPtr)->dataSent +=result;

               if((*currentConnPtr)->dataSent >= (*currentConnPtr)->dataToSend)
                       (*currentConnPtr)->isReading = 1;
                               }

                       }

                       currentConnPtr = &((*currentConnPtr)->next);
                printf("Sending as Slave Thread id = '%d' \n",pthread_self());
               }
           /*
                Проверка принадлежности дескриптора listenSocket
                к множеству readFdSet,т.е. необходимости обработать
                вызов connect( )  от  нового клиента.
           */
       if(FD_ISSET(listenSocket,&readFdSet))
               {
                       
  while(1)
       {

        /*
            Вызовы pthread_mutex_lock, pthread_mutex_unlock
            Не нужны в среде Linux
         */
        pthread_mutex_lock(&request_mutex);
           int result = accept(listenSocket,(struct sockaddr*)NULL,NULL);
        pthread_mutex_unlock(&request_mutex);              
       if(result < 0)
       {

               if(errno==EAGAIN || errno == EWOULDBLOCK)
                       break;
                       die("accept()",errno);
                       }
       else
       {
               *currentConnPtr = malloc(sizeof(struct connection_cb));
               if(*currentConnPtr==NULL)
               die("malloc()",0);
       
               if(fcntl(result,F_SETFL,O_NONBLOCK)<0)
                       die("fcntl()",errno);

               (*currentConnPtr)->dataSocket = result;
                    (*currentConnPtr)->isReading = 1;
               (*currentConnPtr)->next = 0;
               currentConnPtr = &((*currentConnPtr)->next);
       printf("Accepting  as Master Thread id = '%d' \n",pthread_self());
                               }
                       }       
               }

       }
}
int
main(int argc,char *argv[])
{
int k;
int descSock;
char *service="1500";
switch(argc) {
case 1:
 break;
case 2:
 service = argv[1];
 break;
default:
 printf ("Usage: ./ServerBNTH [port]\n");
 exit(1);
}
                                                                                
size_t stacksize;
pthread_t p_thread[NUM_THREADS];

/*
 Установка размера стека для ведомых потоков
*/

pthread_attr_t attr;
   pthread_attr_init(&attr);
   stacksize = 500000;
   pthread_attr_setstacksize (&attr, stacksize);
   pthread_attr_getstacksize (&attr, &stacksize);

/*
  Получение значения дескриптора пассивного сокета
*/ 

   descSock  = getServerSocket(atoi(service));

/* 
 Запуск ведомых потоков
*/

for(k=0; k<NUM_THREADS; k++) {

  pthread_create(&p_thread[k],&attr,serv_request,(void*)descSock);
  printf("Thread %d started \n",k);
}
                                                                               
pthread_attr_destroy(&attr);

for(k=0;k<NUM_THREADS;k++) {
  pthread_join(p_thread[k], NULL);
  printf("Completed join with thread %d\n",k);
 }

}

Ниже приведен модифицированный код square_svc.c (для шаблона square.x), позволяющий скомпилировать многопотоковый сервер RPC в среде Red Hat Linux 9.0 Шаблон square.x: struct square_in { long arg1; }; struct square_out { long res1; }; program SQUARE_PROG { version SQUARE_VERS { square_out SQUAREPROC(square_in) = 1; } = 2 ; } = 0x31230000; Вызов rpcgen для генерации заглушек клиента,сервера и xdr файла : $ rpcgen -a -M square.x
Код процедур сервера: /* ServerSideProc.c */ #include "square.h" #include <stdio.h> #include <stdlib.h> #include <rpc/pmap_clnt.h> #include <string.h> #include <memory.h> #include <sys/socket.h> #include <netinet/in.h> int request=0; bool_t squareproc_2_svc(square_in *inp,square_out *outp,struct svc_req *rqstp) { printf("Thread id = '%ld' started, arg = %d\n",pthread_self(),inp->arg1); /* Имитация работы процедуры , выполняемой потоками сервера */ sleep(5); outp->res1=inp->arg1*inp->arg1; printf("Thread id = '%ld' is done %d \n",pthread_self(),outp->res1); return(TRUE); } int square_prog_2_freeresult(SVCXPRT *transp,xdrproc_t xdr_result, caddr_t result) { xdr_free(xdr_result,result); return(1); }
Модифицированный файл square_svc.c: /* square_svc.c * Please do not edit this file. * It was generated using rpcgen. */ #include "square.h" #include <stdio.h> #include <stdlib.h> #include <rpc/pmap_clnt.h> #include <string.h> #include <memory.h> #include <sys/socket.h> #include <netinet/in.h> #ifndef SIG_PF #define SIG_PF void(*)(int) #endif pthread_t p_thread; pthread_attr_t attr; /* Процедура выполняемая потоком */ void * serv_request(void *data) { struct thr_data { struct svc_req *rqstp; SVCXPRT *transp; } *ptr_data; { union { square_in squareproc_2_arg; } argument; union { square_out squareproc_2_res; } result; bool_t retval; xdrproc_t _xdr_argument, _xdr_result; bool_t (*local)(char *, void *, struct svc_req *); /* Распаковка данных , переданных в процедуру при запуске потока. */ ptr_data = (struct thr_data *)data; struct svc_req *rqstp = ptr_data->rqstp; register SVCXPRT *transp = ptr_data->transp; switch (rqstp->rq_proc) { case NULLPROC: (void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL); return; case SQUAREPROC: _xdr_argument = (xdrproc_t) xdr_square_in; _xdr_result = (xdrproc_t) xdr_square_out; local = (bool_t (*) (char *, void *, struct svc_req *))squareproc_2_svc; break; default: svcerr_noproc (transp); return; } memset ((char *)&argument, 0, sizeof (argument)); if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) { svcerr_decode (transp); return; } /* Стандартный вызов функции сервера. Данные для вызова уже приведены к стандарту. */ retval = (bool_t) (*local)((char *)&argument, (void *)&result, rqstp); if (retval > 0 && !svc_sendreply(transp, (xdrproc_t) _xdr_result, (char *)&result)) { svcerr_systemerr (transp); } if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) { fprintf (stderr, "%s", "unable to free arguments"); exit (1); } if (!square_prog_2_freeresult (transp, _xdr_result, (caddr_t) &result)) fprintf (stderr, "%s", "unable to free results"); return; } } /* Принципиально измененный код square_prog_2 , стартующей теперь новый поток для каждого инициированного клиентом вызова процедуры на удаленном сервере */ static void square_prog_2(struct svc_req *rqstp, register SVCXPRT *transp) { struct data_str { struct svc_req *rqstp; SVCXPRT *transp; } *data_ptr =(struct data_str*)malloc(sizeof(struct data_str); { /* Упаковка данных в структуру для передачи ссылки на нее, как параметра запускаемому потоку */ data_ptr->rqstp = rqstp; data_ptr->transp = transp; pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); pthread_create(&p_thread,&attr,serv_request,(void *)data_ptr); } } int main (int argc, char **argv) { register SVCXPRT *transp; pmap_unset (SQUARE_PROG, SQUARE_VERS); transp = svcudp_create(RPC_ANYSOCK); if (transp == NULL) { fprintf (stderr, "%s", "cannot create udp service."); exit(1); } if (!svc_register(transp, SQUARE_PROG, SQUARE_VERS, square_prog_2, IPPROTO_UDP)) { fprintf (stderr, "%s", "unable to register (SQUARE_PROG, SQUARE_VERS, udp)."); exit(1); } transp = svctcp_create(RPC_ANYSOCK, 0, 0); if (transp == NULL) { fprintf (stderr, "%s", "cannot create tcp service."); exit(1); } if (!svc_register(transp, SQUARE_PROG, SQUARE_VERS, square_prog_2, IPPROTO_TCP)) { fprintf (stderr, "%s", "unable to register (SQUARE_PROG, SQUARE_VERS, tcp)."); exit(1); } svc_run (); fprintf (stderr, "%s", "svc_run returned"); exit (1); /* NOTREACHED */ } Компиляция ServerSQUARE: $ gcc -o ServerSQUARE ServerSideProc.c square_svc.c square_xdr.c -lprthread -lnsl
Код клиента: /* * ClientSideProc.c */ #include <memory.h> /* for memset */ #include "square.h" #include <stdio.h> #include <stdlib.h> #include <rpc/pmap_clnt.h> #include <string.h> #include <memory.h> #include <sys/socket.h> #include <netinet/in.h> int main (int argc,char **argv) { CLIENT *cl; square_in in; square_out out; if (argc != 3 ) { printf ("Usage : client <hostname> <integer_valus=e>\n"); exit(1); } cl = clnt_create(argv[1],SQUARE_PROG,SQUARE_VERS,"tcp"); if (cl == NULL) { clnt_perror (cl, "call failed"); exit (1); } in.arg1 = atol(argv[2]); if (squareproc_2(&in,&out,cl) != RPC_SUCCESS) { printf ("%s\n" , clnt_perror (cl,argv[1] )); exit(1); } printf("result: %ld\n",out.res1); exit(0); } Компиляция ClientSQUARE: $ gcc -o ClientSQUARE ClientSideProc.c square_clnt.c square_xdr.c -lprthread -lnsl
Далее приведем результаты тестирования (сp. [3] ,Глава "SUN RPC"): [root@dell4500 SQWMT]# cat square.bsh ./ClientSQUARE dell4500.redhat 10 & ./ClientSQUARE dell4500.redhat 11 & \ ./ClientSQUARE dell4500.redhat 12 & ./ClientSQUARE dell4500.redhat 21 & \ ./ClientSQUARE dell4500.redhat 13 & ./ClientSQUARE dell4500.redhat 14 & \ ./ClientSQUARE dell4500.redhat 15 & ./ClientSQUARE dell4500.redhat 16 & \ ./ClientSQUARE dell4500.redhat 17 & ./ClientSQUARE dell4500.redhat 18 & \ ./ClientSQUARE dell4500.redhat 19 & ./ClientSQUARE dell4500.redhat 20 & Вывод на машине клиента: [root@dell4500 SQWMT]# ./square.bsh [root@dell4500 SQWMT]# result: 196 result: 225 result: 256 result: 289 result: 121 result: 144 result: 441 result: 169 result: 100 result: 324 result: 361 result: 400 Вывод на машине сервера: [root@dell4500 SQWMT]# ./ServerSQUARE Thread id = '1082453184' started, arg = 14 Thread id = '1090841664' started, arg = 15 Thread id = '1099230144' started, arg = 16 Thread id = '1116941120' started, arg = 17 Thread id = '1125329600' started, arg = 11 Thread id = '1133718080' started, arg = 12 Thread id = '1142106560' started, arg = 21 Thread id = '1150495040' started, arg = 13 Thread id = '1158883520' started, arg = 10 Thread id = '1167272000' started, arg = 18 Thread id = '1175660480' started, arg = 19 Thread id = '1184048960' started, arg = 20 Thread id = '1082453184' is done 196 Thread id = '1090841664' is done 225 Thread id = '1099230144' is done 256 Thread id = '1116941120' is done 289 Thread id = '1125329600' is done 121 Thread id = '1133718080' is done 144 Thread id = '1142106560' is done 441 Thread id = '1150495040' is done 169 Thread id = '1158883520' is done 100 Thread id = '1167272000' is done 324 Thread id = '1175660480' is done 361 Thread id = '1184048960' is done 400 Литература:

1.Дуглас Э. Крамер,Дэвид Л. Стивенс. Сети TCP/IP .Разработка приложений Типа клиент/сервер для LINUX/POSIX . Том 3 Издательский дом "Вильямс",2002
2. http://dlenev.nm.ru/
3.Стивенс У. UNIX: Взаимодействие процессов.Том 1,2 Из-во "Питер",2002

Автор: Б.А. Державец

Комментарии: (0) | Linux | 2006-06-05

Русификация slackware 10.0

Русификация slackware 10.0

Итак, начнем по шагам русифицировать Linux дистрибутив Slackware Linux 10.0

Консоль

1. Откорректируем /etc/rc.d/rc.font и сделаем его исполняемым:

setfont Cyr_a8x16
mapscrn koi2alt
for n in 1 2 3 4 5 6;
do
echo -ne "3(K" > /dev/tty$n
loadkeys ru-ms.map
done

2. открываем файл и там прописываем /etc/profile.d/lang.sh:

#!/bin/sh
export LC_ALL=
export LANG=ru_RU.KOI8-R
export LC_NUMERIC=C
export LC_TIME=ru_RU.KOI8-R
export LC_COLLATE=ru_RU.KOI8-R
export LC_MONETARY=ru_RU.KOI8-R
export LC_MESSAGES=ru_RU.KOI8-R
export LC_PAPER=ru_RU.KOI8-R
export LC_NAME=ru_RU.KOI8-R
export LC_ADDRESS=ru_RU.KOI8-R
export LC_TELEPHONE=ru_RU.KOI8-R
export LC_MEASUREMENT=ru_RU.KOI8-R
export LC_IDENTIFICATION=ru_RU.KOI8-R

3. В файле /usr/share/locale/locale.alias: меняем строчку:

russian ru_RU.ISO8559-5

на

russian ru
ru ru_RU
ru_RU ru_RU.KOI8-R

4. Еще можно заменить строчку:

NROFF /usr/bin/nroff -S -mandoc

на

NROFF /usr/bin/nroff -S -Tcp1251 -mandoc

в файле /lib/man.conf, что бы нормально отображались русские маны.

5. Также можно добавить (файл /etc/profile) путь к русским манам:

export MANPATH=/usr/man/ru:/usr/local/man:/usr/man:/usr/X11R6/man,

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

export LANG=ru_RU.KOI8-R

6. создаем в папке /etc/skel файл .inputrc и прописываем в нем:

set meta-flag on
set convert-meta off

7.X-Window
7.1 Лезем в папку /etc/fonts и открываем файл fonts.conf

и пишем там:



    /usr/share/fonts/TTF

    /usr/X11R6/lib/X11/fonts/Type1

    /usr/X11R6/lib/X11/fonts

    /usr/share/fonts

    ~/.fonts

7.2 осталось дело за малым(научить иксы менять раскладку клавиатуры)!!
лезем в папку /etc/X11 и открываем вайл xorg.conf и ищем блок:

# **********************************************************************
# Core keyboard's InputDevice section
# **********************************************************************

Section "InputDevice"

Identifier "Keyboard1"
Driver "Keyboard"
# For most OSs the protocol can be omitted (it defaults to "Standard").
# When using XQUEUE (only for SVR3 and SVR4, but not Solaris),
# uncomment the following line.

# Option "Protocol" "Xqueue"

# Set the keyboard auto repeat parameters. Not all platforms implement
# this.

# Option "AutoRepeat" "500 5"

# Specifiy which keyboard LEDs can be user-controlled (eg, with xset(1)).
...........
..........
.........
# These are the default XKB settings for X.Org
#
# Option "XkbRules" "xorg"
# Option "XkbModel" "pc101"
# Option "XkbLayout" "us"
# Option "XkbVariant" ""
# Option "XkbOptions" ""

EndSection

меняем этот блок на:

Section "InputDevice"

Identifier "Keyboard1"
Driver "Keyboard"
Option "AutoRepeat" "500 30"
Option "XkbModel" "pc105"
Option "XkbLayout" "us,ru"
Option "XkbOptions" "grp:ctrl_shift_toggle,grp_led:scroll"
Option "XkbRules" "xorg"

EndSection

Вот и все ребятки!!! Приятного пользования Linux Slackware 10....
На мой взгляд это лучшая операционная система для домашнего компьютера

Автор: Kernql^msk
Если вы обнаружили неточности - пишите.

Материал взят с сайта linux.ru

Комментарии: (0) | Linux | 2006-06-05


Страница 9 из 51Первая«6789101112 »Последняя