Intro Этот номер самый особенный. Из всех журналов, которыми я занимался, на верстку этого ушло больше всего времени. По сути, журнал я начал готовить и потихоньку верстать еще с 8 августа. Большая часть статей на тот момент уже была. В планах был намечен выпуск журнала к концу августа, но потом стали появлятся всякие непредвиденные обстоятельства. Сначала я готовился к экзамену в ГАИ, который в итоге завалил. Как и принято у большинства представителей российской молодежи, усиленная подготовка начанается за ночь до экзамена. Так же было и со мной. Вот только в ночь перед экзаменом, я весело попивал пиво с Lord_of_fear, обсуждая Linux J. Что из этого получилось - уже говорил. Ничего, в следующий раз точно выучу. После провала я вернулся в г. Хабаровск, где усиленно начал … искать новую работу. Работа нашлась довольно быстро и вот я уже 1С программист. Честно говоря я никогда не хотел всерьез задумываться об изучении 1С:Предприятия, но теперь я изменил свою точку зрения. Несмотря на большое количество багов и довольно высокие системные требования (я про 1С 8.0), этот «конструктор» очень сильно облегчает создания систем для автоматизации учета деятельности предприятия. К тому же как показывается практика, созданные в 1С сложные конфигурации так или иначе требуют поддержки со стороны программиста, а значит, выучив 1С можно не боятся некоторое время остаться без работы. Сегодняшняя интра как-то не особо мне удалась, поэтому я ставлю точку и желаю тебе приятного чтения. Будут вопросы, обязательно пиши мне на мыло.
Spider_NET
Идея: Фленов Михаил aka Horrific (horrific@vr-online.ru) Редактор номера: Spider_NET (antonov.igor.khv@gmail.com) Графика в журнале: KeyWarez (keywarez@yandex.ru), Spider_NET (antonov.igor.khv@gmail.com) Текущий состав VR-Group:
Horrific, LittleBudda, KeyWarez, Romul, tripsin, Lord_Of_Fear, Spider_NET. Контакты: mail@vr-online.ru, www.vr-online.ru Информация к размышлению: Данный журнал распространяется в виде PDF файлов. Вы можете выкладывать номера на любые носители без изменения внешнего вида журнала, без перевода в другие форматы, без изменения самого файла. В журнал запрещается вносить изменения. Перепечатка материалов запрещена. Журнал распространяется бесплатно, и ты можешь скачать его с нашего сайта, поэтому мы не видим смысла в перепечатывании материалов. Если ты хочешь стать автором журнала, то присылай свою статью на наш e-mail, и мы обязательно включим её в очередной номер.
Содержание номера:
INTRO .......................................................................................................................... 2 КОДИНГ...................................................................................................................... 4 FTP КЛИЕНТ СВОИМИ РУКАМИ .................................................................................... 5 DЕЛЬФИНИЙ ДZЕН №2. ПОЛУПЕРЕМЕЩАЕМЫЙ КОД ................................................. 14 ТАЙНА ЗЕЛЕНОГО ГЛАЗА ИЛИ RADMIN СВОИМИ РУКАМИ .......................................... 21 ПОДКАЧКУ - ПОД КОНТРОЛЬ!..................................................................................... 30 ПОТОКИ И ПЛАНИРОВАНИЕ ВЫПОЛНЕНИЯ ................................................................. 33 РАЗРАБОТКА МНОГОПОТОЧНЫХ ПРИЛОЖЕНИЙ .......................................................... 36 БАЗЫ ДАННЫХ ...................................................................................................... 45 РАБОТА С ORACLE. ЧАСТЬ 3...................................................................................... 46 РАБОТА С ORACLE. ЧАСТЬ 4...................................................................................... 56 ИНФОРМАЦИОННЫЕ ТЕХНОЛОГИИ............................................................. 62 НАВЕСНАЯ ЗАЩИТА VS ИНТЕГРИРОВАННАЯ.............................................................. 63 УДАЛЕННОЕ УПРАВЛЕНИЕ ......................................................................................... 70 ОРИЕНТАЦИЯ НА СЕРВИСЫ........................................................................................ 80 МИГРАЦИЯ В ОТКРЫТЫЙ СТАНДАРТ .......................................................................... 86 БЕЗ РАМКИ.............................................................................................................. 93 ANKLAV, ИЛИ ЛЕС ТАМ ====>................................................................................. 94
Кодинг
FTP клиент своими руками Админим удаленные компы Подкачку - под контроль! Потоки и планирование выполнения Разработка многопоточных приложений
FTP клиент своими руками Вступление Одной из самых часто используемых в повседневной жизни программ продвинутого пользователя – FTP-клиент. Закачать html-странички на сервер, слить warez с сервака, качнуть фильмов в локалке – работа FTP клиента. Стоимость таких программ на рынке колеблется от 10 до 100 баксов. Скажи, тебе не хочется срубить столько же, да еще и не особо напрягаясь? Если ты решительно ответил «Да», то усаживайся по удобнее и продолжай читать статью, познавая секреты программирования ftp-клиентов.
Теория FTP протокола File transfer protocol (Протокол передачи файлов) берет свое начало с 70-х годов. Именно в то время, возникла необходимость в создании протокола, который смог бы решить проблему передачи файлов с одного компьютера к другому. На протяжении 30 лет протокол неоднократно изменялся и совершенствовался. Последняя спецификация протокола приведена в RFC 959 (http://athena.vvsu.ru/docs/tcpip/rfc/rfc959.txt). Я крайне рекомендую тебе скачать этот документ и хорошенько с ним ознакомиться, т.к. только в нем ты найдешь ответы на вопросы, которые могут у тебя возникнуть при написании полноценного FTP-клиента. Как и большинство сетевых протоколов (HTTP, POP3, SMTP и т.д.), ftp работает поверх TCP. В отличие от всех перечисленных протоколов, FTP, обладает одной интересной особенностью. Для полноценной работы ему нужно не одно, а целых два соединения: 1. Управляющее – используется на протяжении всего сеанса связи. По этому соединению отправляются все команды для FTP-сервера и возвращаются результаты их выполнения. 2. Соединение для передачи данных – создается в момент, когда нужно получить/отправить данные (список файлов, передать/скачать файл). После завершения передачи данных, соединение должно завершиться.
Установка соединения Давай подробно рассмотрим процесс установки связи с FTP-сервером. Чтобы выполнить какую-либо команду, клиенту нужно установить управляющие соединение. Сделать это, можно подключившись на 21 порт (порт по умолчанию у большинства FTP серверов) удаленного компьютера. Как только соединение будет установлено, FTP-сервер отправит приветствие. Обычно в нем содержится название используемого сервера и другие информационные данные. Для продолжения работы клиенту необходимо пройти авторизацию – отправить серверу свой логин и пароль. Логин передается командой USER [имя пользователя], а пароль командой PASS [твой пароль]. Если введенные данные окажутся верными, то сервер радостно отправит сообщение с кодом «230 OK». Текст этого сообщения означает, что авторизация успешно пройдена и можно, отправлять возможные команды. Наглядный пример установки управляющего соединения ты можешь увидеть на рисунке 1. На нем изображено, как с помощью telnet я подсоединился к ftp-серверу.
После установки управляющего соединения можно посылать команды для получения списка файлов или же для копирования самих файлов, но перед этим необходимо установить второе соединение – для передачи данных. Я уже много раз говорил о соединение для передачи данных, но до сих пор ничего не сказал о принципах его создания. Первым делом, программе клиенту необходимо открыть любой свободный порт. Затем, удаленному серверу необходимо послать данные в спец формате, которые будут включать: ip адрес (т.е. реальный твой IP) и порт (тот который ты и открывал для подключения). Все эти данные отправляются с помощью команды PORT. Если ты читал внимательно, то наверное обратил внимание на выражение: «в специальном формате». Чтобы долго не объяснять, покажу на простом примере, а недостающую теорию ты всегда сможешь узнать из RFC-959. Допустим, у клиента в качестве IP адреса у нас 192.168.0.1, а октрытым портом является 31337. В этом случае, команда PORT будет выглядеть следующим образом: PORT 192,168,0,1,122,105. Думаю, разглядеть IP адрес в этой строке тебе удалось, а вот при поиске порта вероятнее всего возникли небольшие проблемы. По спецификации RFC, номер порта нужно передавать двумя числами. В нашем примере это 122 и 105. Теперь ясно для чего эти цифры нужны, но не ясно какое отношение они имеют к порту 31337. Ответ, как и должно, быть ждет в RFC. На основании этого документа, синтаксис команды PORT выглядит следующим образом: PORT n1, n2, n3, n4, n5, n6, где n1-n4 – разделенный запятыми IP адрес, а n5*256+n6 – номер порта. Теперь ясно? Нет? Ок! Бери в руки старый калькулятор и приготовься выполнить простейшие математические операции. Число 122 умножь на 256, в результате получишь 31232. Теперь к результату прибавь 105. Если ты правильно нажал на несколько кнопок калькулятора, то у тебя должно получится число 31337 – порт, который мы и задавали. После отправки команды PORT, сервер проверит отправленные данные и если все тип-топ, то будет создан канал для передачи данных (удаленный сервер установит соединение с твоей программой), а значит, ты сможешь отправить команду LIST, и тебе придет список файлов заданной директории. После передачи данных сервер сам завершит второе соединение.
Первый шаг на пути к FTP клиенту.
Я уже познакомил тебя с теорией FTP протокола, теперь ты знаешь примерный принцип работы программ клиентов, но знаний для реализации своего клиента все же мало. Что ж, заполним этот пробел – перейдем к рассмотрению сетевых функций.
Страшный WinSock API В Delphi есть готовые компоненты, которые существенно облегчают процесс программирования FTP-клиента, но к сожалению, используя их, появляются всякого рода ограничения. Лучше написать свой FTP-клиент полностью самому, для этого мы воспользуемся сетевыми функциями Windows. Научившись ими пользоваться, ты сможешь написать не только FTP-клиент, но и любое другое сетевое приложение. Перед вызовом сетевых функций нужно инициализировать сетевую библиотеку. Для этой цели нужно воспользоваться функцией WSAStartup, которая описана в модуле WinSock.pas следующим образом: WSAStartup (wVersionRequested: word; var WSAData:TWSAData):Integeder; stdcall;
Функции нужно передать два параметра: 1. wVersionRequested – версия запрашиваемой библиотеки – 1.1 либо 2.0. Для корректного указания нужной версии лучше всего воспользоваться функцией MakeWord(). Ей нужно передать два параметра – младший и старший байт, т.е. 1, 1. 2. Указатель на структура WSAData. После успешного выполнения функции, в эту структуру попадет информация об инициализированной библиотеке. Чтобы не занимать лишнее место в статье, я не буду приводить описание структуры TWSAData, при желании ты всегда сможешь его увидеть заглянув в модуль Winsock.pas. В случае, когда функция выполнилась успешно, она вернет нам 0, в противном случае она может вернуть нам следующие коды ошибок: WSASYSNOTREADY – сетевая подсистема не готова к сетевому соединению. WSAEFALUT – неверный указатель на структуру TWSAData. WSAPROCLIM – превышен предел поддерживаемых ОС задач. WSAEINPROGRESS – в блокирующем режиме выполняется операция, нужно дождаться ее завершения. Получить код ошибки можно вызовом функции WSAGetLastError, о которой я расскажу чуть позже, а сейчас мы посмотрим, как можно освободить инициализированную библиотеку WinSock.
function WSACleanup:Integer; stdcall;
Функции ничего не нужно передавать в качестве параметров, т.к. она все что она делает – это освобождает инициализированную библиотеку. По идее, ее можно не вызывать, т.к. в теории, после завершения приложения ОС сама должна это сделать, но чтобы лишний раз не надеяться на программистов из MS лучше освободить библиотеку самостоятельно. function socket (af:integer; type:integer; protocol:integer):TSocket; stdcall;
Функция socket, после своего успешного выполнения возвращает объект типа TSocket, с помощью которого мы и будем работать с сетью. В качестве параметров этой функции необходимо передать: 1. af – семейство протоколов. Наш пример будет использовать только TCP, поэтому в этом параметры будем указывать AF_INET. Про остальные возможные значения этого параметра ты сможешь узнать из модуля WinSock.pas или MSDN. 2. type – тип нового сокета. Может принимать значения SOCK_STREAM (передача данных с установкой соединения) или SOCK_DGRAM (все данные передаются без установки соединения). Поскольку мы будем использовать протокол TCP, то в этом параметре мы будем указывать SOCK_STREAM. 3. protocol – протокол. Для TCP протокола (который и будем мы использовать) нужно передать в этот параметр константу IPPROTO_TCP. function bind (S:TSocket; var addr:TSockAddr; namelen:Integer):integer; stdcall;
Для связывания локального сетевого адреса с сокетом мы должны воспользоваться функцией bind. Это функция пригодится нам для организации канала передачи данных. Давай рассмотрим ее параметры: 1. s – созданный, с помощью функции socket сокет. 2. addr – указатель на структуру TSockAddr. 3. Размер структуры TSockAddr. При успешном выполнении, функция вернет 0, в случае ошибки вернет SOCKET_ERROR. Определить код ошибки можно с помощью функции WSAGetLastError(); В качестве второго параметра нам необходимо передавать указатель на структуру TSockAddr. При программировании сетевых приложений это структура используется повсеместно, поэтому ты должен ее знать также хорошо, как и дырки в своих зубах. Описывается структура следующим образом: Структура SockAddr_IN TSockAddrIN = sockaddr_in; SockAddr_In = record sin_family: u_short; sin_port: u_short; sin_addr:TInAddr; sin_zero: array[0..7] of Char; end;
В структуре присутствуют следующие параметры. 1. sin_family – семейство протоколов. Этот параметр аналогичен первому параметру функции socket. При использовании любых Интернетпротоколов здесь нужно указать AF_INET. 2. sin_port – порт, которые будет использовать наша программа для получения данных. Если указать в этом параметре 0, то система сама присвоит приложению свободный порт. 3. sin_addr – структура SockAddr_IN, в которой хранится информация о IP адресе. 4. sin_zero – совмещение по длине структуры sockaddr_in с sockaddr и наоборот. Для нашего примера данный параметр структуры использоваться не будет. function listen (s:TSocket; backlog:Integer):Integer; stdcall;
После успешного выполнения функции bind, можно приступать к прослушке порта в ожидании гостей. Для это собственно и создана функция listen. Функции нужно передать всего два параметра: 1. s – сокет, который связали с локальным адресом. 2.backlog – максимальное количество запросов на ожидание подключения. Если функция выполнится успешно, то она вернет 0, в противносм случае ошибки, коды которых можно узнать из модуля WinSock.pas. function Accept (S:TSocket; addr: PSockAddr; AddrLen:PInteger):TSocket; stdcall;
Как только клиент сделал попытку подключиться (в случае, если мы выступаем сервером), необходимо принять соединение. Этим нехитрым делом и занимается функция Accept. В качестве параметров функции нужно передать: 1. s - сокет. 2. addr - указатель на структуру SockAddr. 3. AddrLen - размер структуры SockAddr. В случае успешного выполнения, функция Accept возвращает указатель на сокет, через который мы можем работать с подключившимся клиентом. function stdcall;
connect
(s:TSocket;
var
name:TSockAddr;
namelen:integer):integer;
Думаю, рассказывать про предназначение функции connect не нужно, т.к. все и так понятно из ее названия. Из параметров функции нужно передать: 1. сокет. 2. Структура sockAddr, в которой содержатся данные для подключения к серверу (протокол, адрес, порт). 3. Размер структуры sockAddr. Как и большинство сетевых функций, в случае успешного выполнения данная функция вернет нам 0. function send (s:TSocket; var Buf; len:Integer; flags:integer):Integer; stdcall;
Для отправки данных в наборе Winsock есть несколько функций, среди которых имеется функция с именем send. Рассмотрим ее параметры: 1. s - сокет, который будет использоваться для отправки данных. 2. buf – буфер, в котором содержатся данные для отправки. 3. len – размер буфера. 4. flags – флаги, влияющие на метод отправки. Для нашего примера можно просто указать 0. Если функция выполнится успешно, т.е. сможет отправить данные, то в качестве результата она вернет количество фактически отправленных данных, в противном случае вернет ошибку. function recv (s:TSocket; var buf; len:integer; flags:integer):Integer; stdcall;
Функция выполняет противоположную роль функции send – она принимает данные. Ее параметры полностью идентичны параметрам функции send, поэтому не будем тратить время и рассматривать их еще раз. function CloseSocket (s:TSocket):integer; stdcall;
Эта функция необходима для закрытия сокета. По правилам хорошего тона ее принято вызвать после функции shutdown, тем немее, программисты пренебрегают этим правилом и вызывают ее сразу, забывая про shutdown. function WSAGetLastError:integer; stdcall;
С помощью этой полезной функции можно получить код возникшей ошибки при вызове какойлибо другой функции. Вызвав WSAGetLastError(), она сразу же вернет код последней возникшей в системе ошибки. В последствии его можно проанализировать и довести до пользователя.
Строим FTP клиента
Ну вот, и настал тот момент, когда нам нужно закрепить все теоретические знания практикой. Запускай Delphi и создавай новый проект типа Application. На форму брось один компонент TRichEdit и один TMainMenu. TRichEdit у меня растянуто по всей форме, а в TMainMenu созданы элементы меню: 1. Соединение - Подключиться - Отключиться - Настройки 2. Команды - LIST - CWD Мою готовую форму ты можешь увидеть на рисунке 3. По нажатию на кнопку «Настройки» будет вызываться дополнительная форма, в которой нужно будет ввести: имя пользователя, пароль, сервер, порт. Ее вид можно посмотреть на рисунке 4.
Форма программы
Форма для ввода настроек
Кодинг Простенький дизайн нашего FTP-клиента готов теперь можно начинать готовить начинку – писать код. Первым делом не забудь подключить к нашему проекту модуль Winsock.pas, иначе вызов сетевых функций будет невозможен. Теперь необходимо объявить все необходимые переменные. В разделе private объяви следующие переменные:
_wsaData:TWSADATA; _clientSocket:TSocket; _serverSocket:TSocket; _clientAddr:sockaddr_in; _serverAddr:sockaddr_in; _mode:integer; _tempSocket:TSocket;
Об их предназначении ты узнаешь по ходу рассмотрения примера. При описании сетевых функций я говорил, что перед их использованием нужно проинициализировать сетевую библиотеку. Инициализацию сетевой библиотеки я делаю во время создания формы, а ее освобождение во время закрытия окна. Если у тебя возникли проблемы с инициализацией библиотеки, то открывай исходник на нашем DVD и сравнивай. После инициализации сетевой библиотеки можно попытаться соединиться с удаленным сервером. По нажатию кнопки «Соединиться» у меня вызывается самописная процедура _connect(), которой нужно передать все необходимые для подключения данные (адрес сервера, логин, пароль, порт). Код этой процедуры ты можешь увидеть в листинге 2.
Листинг № 2 procedure TForm1._Connect(ftp_server, ftp_port, user_name, user_pass: string); begin _clientsocket:=SOCKET(AF_INET, SOCK_STREAM, IPPROTO_IP); if _clientSocket=INVALID_SOCKET then begin GetError('Socket'); Exit; end; _clientAddr.sin_family:=AF_INET; _clientAddr.sin_addr.S_addr:=htonl(INADDR_ANY); _clientAddr.sin_addr.S_addr:=inet_addr(pchar(ftp_server)); _clientAddr.sin_port:=htons(StrToInt(ftp_port)); WSAAsyncSelect(_clientSocket, handle, WM_MYSOCKMESS, FD_READ); Connect(_clientsocket, _clientaddr, sizeof(_clientaddr)); Sleep(100); _send(_clientsocket, 'USER '+user_name); _send(_clientsocket, 'PASS '+user_pass); _send(_clientSocket, 'FEAT');
Весь код установки соединения с удаленным сервером отображен в листинге 2, поэтому давайка рассмотрим его содержимое подробно. В самом начале я создаю новый сокет. Ты уже знаешь, для того чтобы создать новый сокет нужно воспользоваться функцией SOCKET, которая после выполнения возвратит указатель на созданный сокет. После вызова функции SOCKET, я проверяю, а не возникла ли ошибка. Если да, то я вызываю самописную процедуру GetError, передав ей название функции вызываемой функции. Процедура GetError попытается получить код ошибки и в конце концов проинформирует пользователя, напечатав в TRichEdit соответстующий текст. Код процедуры GetError ты можешь посмотреть, открыв исходник примера, любезно дожидающийся тебя на нашем диске. Если ошибки не возникло, то можно начинать готовится к соединению с удаленным сервером. Как ты должен помнить, чтобы установить соединение с сервером нужно вызвать функцию
connect, которой нужно передать структуру типа sockaddr_in. Ну а чтобы ее передать, ее нужно заполнить, что я и делаю. После заполнения структуры, я вызываю функцию WSAAsyncSelect(). Данная функция устанавливает асинхронный режим для выбранного сокета и заставляет Windows генерировать сообщения для сетевых событий. Таким образом, нам достаточно указать сообщение, которое должно приходить окну нашего приложения при возникновении события на определенном сокете. На первый взгляд может показаться, что использование этого метода тяжело в реализации, но на самом деле это не так и через несколько минут ты в этом убедишься, но сначала, давай взглянем на параметры, которые нужно передать функции. 1. s – сокет, за событиями которыми необходимо наблюдать. 2. hWindow – окно, которое будет принимать сообщения. 3. wMsg – системное событие, которое нужно генерировать. 4. lEvent – сетевые события, за которыми мы будем наблюдать. В качестве событий ты можешь указать: FD_READ (возникает когда пришли данные), FD_WRITE (возникает когда можно передавать данные), FD_OOB (возникает когда прибыли срочные данные), FD_ACCEPT (возникает когда в очереди сокета есть новое подключение), FD_CONNECT (возникает при соединении с сервером). В качестве третьего параметра я указал лишь FD_READ. В момент, когда на наш сокет придут данные, главное окно нашего приложения получит сообщение WM_MYSOCKMESS. Чтобы не прозевать сообщение, нам нужно написать процедуру, которая будет перехватывать нужное сообщение. Перед тем как дать код процедуры я хотел бы объяснить тебе, что из себя представляет WM_MYSOCKMESS. В нашем примере это константа, которая объявлена мной и равна WM_USER+1. Что такое WM_USER? Это число. Все числа меньше этого могут уже использоваться системой, поэтому чтобы не было конфликтов, можно нужно просто использовать это число + 1. Немного отвлечемся от рассмотрения функции WSAAsyncSelect() и вернемся к разбору листинга 2. Сразу после WSAAsyncSelect() вызывается функция Connect, которая начинает устанавливать соединение с удаленным сервером. После выполнения функции Connect я сразу начинаю отправлять данные для прохождения авторизации (вспоминай теорию). Отправка данных реализована в самописной функции _send(). В качестве параметров ей нужно передать сокет, через который будут отправлены данные и сами данные. Теперь вернемся к интересной функции WSAAsyncSelect(). Я уже говорил, что для перехвата нужного события нужно объявить специальную процедуру. В примере, я объявил ее в разделе private следующим образом: procedure NetMSG (var M:TMessage); message WM_MYSOCKMESS;
Код тела процедуры ты можешь увидеть в листинге 3. Как видно из описания, в процедуру передается структура типа TMessage. В этой структуре имеется несколько параметров, но нас будут интересовать только два: WParam и LParam. В первом хранится дескриптор сокета на котором произошло событие, а во втором тип события. Для проверки типа события я использую управляющую структуру CASE, в которой проверею интересующие меня события.
Листинг 3 procedure TForm1.NetMSG(var M: TMessage); begin case m.LParam of FD_ACCEPT: begin _tempSocket:=accept(m.WParam, nil, nil); WSAAsyncSelect(_tempSocket, handle, WM_MYSOCKMESS, FD_READ+FD_CLOSE); end;
FD_READ: _recv(m.WParam); FD_CLOSE: CloseSocket(M.WParam); end; end;
При возникновении события FD_READ вызывается процедура _recv, которая и выполняет чтение данных с определенного сокета. Код процедуры _recv и _send (для отправки данных) ты можешь увидеть в исходнике примера.
Тестирование Наш пример на половину готов, теперь самое время протестировать его работоспособность. Попробуем скомпилить наше приложение, и подцепиться к какому-нибудь ftp серверу. Результат моего тестирования ты можешь увидеть на рисунке 5. Для теста я подцепился к серверу своего хостера и успешно прошел авторизацию.
Disconnect Рассмотреть весь код FTP-клиента в рамках одной статьи просто невозможно. Поэтому, разбираться с установлением второго соединения (для передачи данных) тебе придется самостоятельно. Сильно по этому поводу не переживай. Ты всегда можешь заглянуть на наш диск и посмотреть исходник FTP-клиента в котором я уже реализовал получения списка файлов определенной директории. Весь исходник я постарался максимально прокомментировать, поэтому с пониманием возникнуть проблем не должно. В крайнем случае, ты всегда можешь задать мне вопрос на мыло. by Антонов Игорь E-Mail: antonov.igor.khv@gmail.com
Dельфиний дZен №2. Полуперемещаемый код Продолжение. Начало в номере за июль 2007г Эту часть правильнее было бы назвать «Вызов функций по абсолютному адресу», но это звучит еще непонятнее, и куда менее амбициозно. Такую безумную идею я больше нигде не встречал и считаю ее своим изобретением :) Возможно, ты слышал, что вирмейкеры при разработке своих вирусов частенько добавляют в них разные вредоносные функции. При этом они делают свой код «перемещаемым». Это значит, что этот код сможет работать в любом месте памяти и не привязан жестко в каким-то объектам (ведь вирмейкер фактически не знает в каком конкретном месте окажется его код после переполнения буфера). Такой код я покажу в третьей части. Одна из основных проблем перемещаемого кода - вызов внешних функций. Дело в том, что при вызове функции, компилятор использует не абсолютный адрес, а смещение относительно места вызова функции. Поясню на примере: program Project1; uses Dialogs; begin ShowMessage('Пример'); end.
Ставим бряк(breakpoint) на ShowMessage и запускаем. Смотрим окно CPU (если ты уже забыл, то его удобнее вызывать с помощью CTRL-ALT- C):
По адресу $00451F71 лежит команда E8D2FBFFFF E8 – это CALL (относительный ближний вызов). Запускаем калькулятор, переключаем в HEX-режим (4 байта) и считаем: $451F71 + $5 + $FFFFFBD2 = $451B48; 5 - длина команды CALL; FFFFFBD2 - смещение (не забывай, что младшие байты числа лежат по младшим адресам). Получаем $451B48 и переходим по этому адресу (CTRL-G):
Попали как раз в начало функции ShowMessage! Надеюсь я понятно объяснил относительную адресацию. Теперь представь, что мы переместили код, содержащий вызов функции ShowMessage, куданибудь в кучу. И оказался ее вызов где-нибудь по адресу $00860828. Если снова посчитать
смещения перехода, то получится адрес $008603FF, естественно здесь никакого вызова ShowMessage не будет, а будет ошибка доступа. Таким образом, чтобы создать перемещаемый код, надо научиться вызывать функции не по относительному смещению, а по абсолютному адресу. Что тебе это даст? Ты сможешь переместить код своей функции в другое место, например в кучу, стек, в адресное пространство какой-нибудь dll’ки, и спрячешь ее вызов от отладчика. В общем идея состоит в том, чтобы вызывать функцию по указателю. А для того, чтобы нормально использовать параметры, этот указатель будем приводить к прототипу этой самой функции. Полное извращение. :) Смотри сам: program Project1; uses Dialogs; // Прототип функции ShowMessage type _ShowMessage = procedure (const Msg: string); begin // Вызов функции по указателю _ShowMessage(@ShowMessage)('Test'); end.
Снова запускаем пример и смотрим, во что превратился вызов ShowMessage:
Здесь в регистр EBX непосредственно заносится уже знакомый тебе адрес $451B48, по которому расположена функция ShowMessage. Потом происходит CALL на это содержимое регистра EBX. Никаких относительных смещений нет и этот код будет работать в любом месте адресного пространства твоей программы! Теперь настало время объяснить, почему я назвал этот код полуперемещаемым. Дело в том, что этот код будет работать только в адресном пространстве твоей программы. Если ты попробуешь внедрить его в другую прогу, то снова будет ошибка доступа. Почему? Да потому, что абсолютный адрес $451B48 имеет значение только для твоей проги, а в другой по этому адресу будет лежать что-то совсем другое, но точно не функция ShowMessage. Вот так-то. Кроме того у метода вызова функций по абсолютному адресу есть еще одно совершенно неочевидное ограничение. С API-функциями Windows никаких проблем нет. Но вот в Delphi все функции делятся на настоящие и ненастоящие(встроенные). Отличить их легко и ты сталкивался с этим не раз. Если навести мышку на имя функции и кликнуть по нему, удерживая CTRL, то тебя забросит в место, где эта функция определяется, и ты сможешь посмотреть ее код. Но это относится только к настоящим функциям. Если ты сделаешь то же самое скажем с функцией AssignFile, то тебя забросит куда-то в начало модуля System. Так по крайней мере в Delphi 7. Это пример ненастоящей (встроенной) функции. На место ее вызова компилятор вставляет целый блок своего кода. Поэтому с ненастоящими функциями вызов по указателю не прокатит. Если ты попробуешь сделать так: type _AssignFile = procedure (var f: File; FileName: String); var f: File;
begin … _AssignFile(@AssignFile)(f,'test.txt'); … end.
то компилятор просто откажется тебя понимать и нивкакую не будет компилировать код. Имей это ввиду. Решить эту проблему можно, сделав функцию-переходник, которая будет уже вызывать встроенную функцию. В демо-проекте токой переходник сделан для функции FreeMem. Еще одна засада поджидает тебя при использовании строк. В нашем примере в функцию ShowMessage передается непосредственно указатель на строку, но так бывает далеко не всегда. Строки в Delphi это совсем непростые динамические структуры данных, для обработки которых компилятор вставляет специальный код. Там происходит выделение памяти в куче, всякие контроли границ, обработка исключений и т.п. Лучше всего типом String не пользоваться, а создавать строку непосредственно в функции в виде символьного массива. Примерно так: var str: array[0..4] of Char; … str[0] := 'T'; str[1] := 'e'; str[2] := 's'; str[3] := 't'; str[4] := #0; Это конечно неудобно, но зато надежно. Еще вариант – передавать указатели на строки с параметрах функции. Есть и будут другие подводные камни, например при обработке исключительных ситуаций. Поэтому не забывай про отладчик и постоянно контролируй, чего тебе Delphi там накомпилировала. В качестве рабочего примера мы сейчас соорудим секретную функцию, которая будет прятаться в стеке и записывать имя пользователя в файл. // Пользовательская функция освобождения памяти // Заменим этой функцией ненастоящую функцию FreeMem procedure FreeMemory(P: Pointer); begin FreeMem(P); end; // Секретная функция, которая будет работать в стеке //Получает в параметрах указатели на строки сообщений function Secret(pTitle: PChar; pMessage: PChar): Boolean; stdcall; type // Прототипы использованных Функций _AllocMem = function(Size: Cardinal): Pointer; ........... _MessageBox = function (hWnd: HWND; lpText, lpCaption: PChar; uType: UINT): Integer; stdcall; var FileName: array[0..5] of Char; FileHandle: Integer; UserName: PChar; NameLength: Cardinal; begin
Result := False; //Резервируем память под имя пользователя. NameLength := 256; // Максимальная длина имени пользователя UserName := _AllocMem(@AllocMem)(NameLength); // Получаем имя пользователя _GetUserName(@GetUserName)(UserName,NameLength); // Создаем строку с именем файла 'х.txt' FileName[0] := 'x'; FileName[1] := '.'; // Строки надежнее всего создавать так. FileName[2] := 't'; FileName[3] := 'x'; FileName[4] := 't'; FileName[5] := #0 ; // Не забываем терминальный нуль // Создаем файл для записи. В модуле SysUtils есть функция FileCreate, но // она использует в параметрах тип String, что приводит к вставке // незапланированного кода, поэтому ее не используем. FileHandle := Integer(_CreateFile(@CreateFile)(@FileName,GENERIC_WRITE, 0, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0)); dec(NameLength); // Обрубаем хвостовой нуль //Пишем в файл имя пользователя if _FileWrite(@FileWrite)(FileHandle,UserName^, NameLength) = NameLength then Result := True; // Освобождаем ресурсы. _FileClose(@FileClose)(FileHandle); // Вызов ненастоящей функции FreeMem мы заменим // на нашу настоящую функцию FreeMemory _FreeMemory(@FreeMemory)(UserName); // Хвалимся успехами if Result then _MessageBox(@MessageBox)(0,pMessage,pTitle,0); end;
Часть прототипов функций и различные проверки опущены для краткости (смотри их в прилагаемом демо-проекте). Имя пользователя получаем как обычно с помощью функции GetUserName и записываем его в файл x.txt. В конце выскакивает окно сообщения с текстом, который передали функции в параметрах. Функция объявлены как stdcall, чтобы четко определиться, что параметры передаются через стек (а не через регистры, как в Delphi по умолчанию), чтобы удобнее было за ними следить в отладчике. Теперь остается зарезервировать память в стеке, переместить туда нашу функцию и передать на нее управление. Для резервирования памяти просто объявим локальный байтовый массив, т.к. все локальные переменные резервируются в стеке. procedure Main; var buf: array[0..511] of Byte; // Место в стеке c запасом …
Ну вот. В стеке у нас есть место на полкилобайта – с запасом на всякий случай. Осталось скопировать туда функцию Secret. Для копирования можно использовать CopyMemory или Move. Move(Secret,buf,FuncLen);
Стоп! А чему равна FuncLen - длина функции Secret? Здесь придется делать допущение, что в скомпилированном коде функции будут располагаться в том же порядке, как мы написали в исходнике (и это действительно так). Поэтому если сделаем так: program Project1; ... function Secret(pTitle: PChar; pMessage: PChar): Boolean; stdcall; ...
end; procedure Main; begin //Здесь копируем в стек функцию Secret ... end; begin Main; end.
и получается, что длину функции можно будет вычислить путем вычитания адреса функции Secret из адреса функции Main: FuncLen := Cardinal(@Main) - Cardinal(@Secret);
И еще один момент. Раньше можно было без проблем выполнять код, расположенный в стеке, но теперь с этим стали жестоко бороться и запрещать исполняемый стек программными а аппаратными средствами. (если хочешь знать больше, то ищи статьи про DEP - Data Execution Prevention) По идее это должно привести с уменьшению количества атак типа buffer overflow (переполнение буфера). Поэтому, чтобы код работал везде, надо явно разрешить исполнение кода в странице памяти стека (куда мы копируем функцию). Станица памяти имеет размер 2 кб и с помощью VirtualProtect нам нужно изменить атрибуты 2-х страниц, на тот случай, если функция окажется в конце первой страницы. VirtualProtect(buf, 2, PAGE_EXECUTE_READWRITE, OldPageProtection);
В общем виде код функции Main выглядит так: procedure Main; var FuncLen: Cardinal; // Размер кода функции buf: array[0..511] of Byte; // Место в стеке c запасом MovedFunction: _Secret; // Указатель на функцию в стеке OldPageProtection: Cardinal;// СТарые аттрибуты страницы памяти title, ok_string: String; // Строки для всплывающего окна begin title := 'Пример выполнения кода в стэке'; ok_string := 'РАБОТА В СТЕКЕ: Файл успешно создан.'; // Загоняем функцию Secret в стэк FuncLen := Cardinal(@Main) - Cardinal(@Secret); Move(Secret,buf,FuncLen); MovedFunction := @buf; //Устанавливаем указатель на начало функции в стеке // Устанавливаем в стеке аттрибут выполнения кода if not VirtualProtect(@buf,2,PAGE_EXECUTE_READWRITE,OldPageProtection) then Exit; try // Запускаем функцию в стеке if MovedFunction(PChar(title), PChar(ok_string)) then ShowMessage('Работа в стеке прошла успешно.') else ShowMessage('Ошибка при работе в стеке.'); // Восстанавливаем аттрибуты страниц VirtualProtect(@buf,FuncLen,OldPageProtection,OldPageProtection); except ShowMessage('Hello hacker!'); end; end;
Код полностью откомментирован. Вопросов быть не должно. Вызов секретной функции находится в блока trу..except. Это надо делать в любом случае. Мало ли что может произойти у
пользователя на компе. Но нам обработка исключений потребуется для совершенно конкретного случаю – ловли взломщика! J Компилим экзешник (до сих пор использую Delphi 7) и запускаем его. Появляются подряд два окошка, которые сообщают, что все идет нормально, а каталоге программы создается файл x.txt с именем пользователя. Теперь попробуем поймать вызов секретной функции. Мы знаем, что имя пользователя получается с помощью функции GetUserName. Поэтому загружаем экзешник в отладчик OllyDbg и ставим точку останова на функции GetUserNameA (bpx GetUserNameA в командной строке). Запускаем на выполнение - вываливается сообщение «Hello hacker!», а отладчик всплывает где-то в ntdll.dll Файл x.txt не создается. Тоже самое происходит при попытке отладить секретную функцию с помощью стандартного отладчика Delphi. Но вот если поставить железный бряк (hardware on execution), то отладчик послушно всплывает посередине стека и позволяет полностью протрассировать код секретной функции. Получился довольно хитрый антиотладочный прием против начинающих взломщиков. Разберемся, как он работает? Обязательно! Когда отладчик ставит бряк, то он ставит на это место специальную инструкцию int 3 (опкод CC), которая вызывает отладочное исключение. Это исключение отладчик отлавливает и сразу заменяет это CC на тот байт, который стоял на этом месте до установки бряка. А теперь смотри, что получается у нас. Вот окрестности вызова GetUserNameA в стеке. Серым подсвечена инструкция, которую заменит отладчик.
Точка останова (инструкция int3) ставится в секции кода на вызове функции GetUserNameA, но этот код никогда не исполняется. Когда мы копируем функцию в стек, то вместе с остальным кодом копируется и инструкция int3.
Но об этой новой точке останова отладчик ничего не знает, т.к. он ее не устанавливал! Поэтому int 3 в коде секретной функции не удаляется. Процессор ее выполняет и возникает исключение. Его-то и ловит блок try..except и приветствует неудавшегося взломщика. И кроме того посмотри как изуродовался код после int3. В случае с железным бряком никакого изменения кода не происходит, поэтому трассировка проходит нормально. Собственно таким образом я и получил эти скриншоты.
Если тебе все еще показалось мало описанных в этой статье извращений, то никто не мешает взять на вооружение технику модификации кода, описанную в первой части. Изменяй код скопированной с стек функции, как твоей душе будет угодно. Здесь я этого делать не стал, чтобы совсем не запутать. В результате идет лесом не только отладчик, но еще и дизассемблер. Можно даже прикрутить к проге простенький дизассембер и удалять из скопированного кода точки останова. Хотя, имхо, это уже стрельба из пушки по воробьям, т.к. железный бряк сведет на нет все усилия. Это все. Ты теперь загружен дзеном по самые уши. J В следующей части будем делать полностью перемещаемый код. Удачного компилирования и … продолжение следует. Исходники примера в архиве delphi1.zip
by Орехов Роман aka tripsin E-mail: tripsin@yandex.ru
Тайна зеленого глаза или RAdmin своими руками В данной статье мы поговорим о создании собственного средства удаленного администрирования. Как же это захватывающе смотреть в своем мониторе, что делает твой сосед по отделу, и понимать, что под его грозным видом скрывается человек с привязанностью к сайтам знакомств и любовью к фотографиям пятничной тематики. Хочу сразу предупредить, что наблюдение штука захватывающее, и может вырасти в навязчивую идею постоянного слежения за всеми и страха что этот фокус провернут с тобой, так что лучше с этим не злоупотреблять:):).
Приступаем Сначала проведем разведку боем, чтобы понять, что предлагает нам рынок готовых продуктов и к чему нам стремиться в собственной реализации данного вида софта. Открой любой поисковик, например GOOGLE и введи "Удаленное администрирование", у меня третий по счету отобразилась самая популярная программа для удаленного администрирования Remote Administrator (www.radmin.ru) или в народе RADMIN. Сейчас мы сделаем ее аналог, в результате у нас появится полезный инструмент совершенно и что самое главное совершенно за бесплатно. Итак, приступим! Запускай дружескую оболочку Delphi, у меня она гордо носит цифру 7. Первым разработаем серверную часть. Размести на форме следующие компоненты (рис.1): -TIdTCPServer (закладка Indy Servers) - как видишь для работы с сетью мы будем использовать компоненты INDY. • •
• •
два TEdit - в них ты будешь вводить IP адрес сервера и номер порта, по которому будет происходить соединение. TButton с текстом "Включить сервер" - с помощью нее ты будешь запускать сервер, тем самым давая возможность подключаться к твоей машине. В конце концов, пользователю все-таки должны оставить право решать самостоятельно хочет он чтобы за ним подсматривали или нет. TMemo - в нем у тебя будет вестись лог всех осуществляемых на сервере операций. TImage - к нему нам потребуется две картинки, которые можно найти в исходниках программы, размещенной на компакт диске. Имена графических файлов необходимых нам eye1.bmp и eye2.bmp. Первая будет характеризовать выключенное состояние сервера, а вторая наоборот активность сервера. Размести компоненты на форме в соответствии с рис.1.
рис. 1
Кодируем сервер Приступаем к коддингу. Для кнопки "Включить сервер" создай обработчик, в котором серверу задается IP адрес и номер порта, на котором будет осуществлять прием команд. Делается это через свойство Bindings, оно является контейнером для всех сокетов, связанных с сервером (смотри плашку "Активизируем сервер"). Дальше необходимо активизировать сервер, посредством установки свойства Active компонента TIdTCPServer в True, при этом кнопка "Включить сервер" превращается в "Выключить сервер" и меняется картинка в TImage, таким образом, пользователь визуально сможет наблюдать состояние сервера. Листинг обработчика ты найдешь в исходниках программы размещенной на компакт диске к журналу. Также нам потребуется специальная процедура Log, она отвечает за журналирование действий осуществляемых сервером. Объяви ее в секции public формы следующим образом: procedure TForm1.Log(S:string);
Реализация ее очень проста: Memo1.Lines.Add(TimeToStr(Time)+'
'+S);
То есть в ней идет обычное добавление строки текста в TMemo, при желании процедуру можно модифицировать записывая данные в файл или еще что-то в этом роде, при чем код самой программы менять не придется. Вот она прелесть правильного построения логики программы. Также нам понадобиться процедура для получения скриншота экрана. Но прежде чем писать ее установи компонент TPNGImage, который позволяет работать с изображениями формата PNG (компонент прилагается вместе с исходниками программы). Объяви в секции public формы процедуру GET_SCREEN. Ее реализация представлена ниже:
Листинг 1: procedure TForm1.GET_SCREEN; var Desktop: TCanvas; B: TBitmap;
W, H :Integer; PNG: TPNGObject; Kursor:TPoint; TempRect:TRect; begin GetCursorPos(Kursor); W:=Screen.Width; H:=screen.Height; TempRect:=Rect(Kursor.x,Kursor.y,Kursor.x+10,Kursor.y+10); B:=TBitmap.Create; B.Width:=W; B.Height:=H; Desktop:=TCanvas.Create; try with Desktop do Handle := GetWindowDC(GetDesktopWindow); with B.Canvas do begin Brush.Color:=clGreen; CopyRect(Rect (0, 0, w, h), DeskTop, Rect(0, 0, w, h)); FillRect(TempRect); end; PNG := TPNGObject.Create; PNG.Assign(B); PNG.SaveToFile(ExtractFilePath(Application.ExeName)+'\'+'s.png'); finally DeskTop.Free; B.Free; PNG.Free; end; end;
С помощью вышеописанной процедуры мы получаем скриншот экрана на месте курсора рисуем зеленый прямоугольник, для чего используем функции GetCursorPos, Rect и FillRect. Полученный графический образ сохраняем в файле s.png (комментарии к коду ты найдешь в исходниках программы размещенной на компакт диске). Итак, мы подошли к финальной ноте нашего произведения о создании сервера. Создай обработчик OnExecute компонента TIdTCPServer, в котором будет происходить анализ присланных команд от клиента и на основании их совершаться необходимые действия.
Листинг 2: procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread); var z: string; fstream:TFileStream; X,Y:integer; K:TPoint; begin with AThread.Connection do begin //Читаем, что прислало нам клиентское приложение z := ReadLn; if SameText(Copy(z, 1, 11), 'get_screen ') then begin
Log('Запрошен скриншот'); GET_SCREEN; fStream TFileStream.Create(ExtractFilePath(Application.ExeName)+'\'+'s.png', fmOpenRead + fmShareDenyNone); //ПЕРЕДАЕМ файл клиентскому приложению OpenWriteBuffer; Log('Передаем файл s.png'); WriteStream(fStream); Log('Файл передан'); CloseWriteBuffer;
:=
FreeAndNil(fStream); end; ... //Обработка остальных команд ... AThread.Connection.Disconnect; end; end;
Здесь приведен лишь фрагмент кода обработчика OnExecute, который отправляет скриншот экрана, остальную часть ты найдешь в исходниках программы, расположенной на компакт диске. Поговорим более детально о командах, которые может принимать наш сервер, с первой вы уже знакомы это "get_screen ". Остальные представлены на схеме, изображенной на рис.2. Во время обращения к серверу каждый клиент создает свой собственный поток, информация о нем как раз и содержится в переменной AThread, из которой мы читаем присланную команду с помощью функции ReadLn. Далее с помощью функции SameText мы осуществляем проверку на факт того, что присланная команда является разрешенной. Затем создаем поток и через него передаем файл клиенту, после чего рвем соединение, так как запрошенное действие выполнено.
Рис 2
Проектируем и кодируем клиентскую часть Я уже чувствую нетерпение, с которым ты хочешь приступить к тестированию разработанной тобой утилиты. Чтобы расслабиться в спинке кресла и никуда не бегая решать все проблемы пользователей удаленно, слушая приятную музыку и попивая еще горячее кофе - красота, да и только. Надеюсь, ты оценишь в эти минуты все прелести работы системным администратором, когда в не зависимости что за окном снег или дождь, ты можешь чувствовать себя "сухо тепло и комфортно":):) Остался последний рывок - разработка клиентской части. Создай новое приложения, не забыв при этом сохранить старое. Размести на форме следующие компоненты (рис.3): • • • • •
•
-TIdTCPClient (закладка Indy Servers) - с помощью него ты будешь соединяться с сервером и посылать ему команды. -TGroupBox и в нем 2 TEdit - в TEdit'ы ты в дальнейшем введешь IP адрес сервера и номер порта по которому будет происходить соединение. -4 TButton с текстом "Скриншот", "Просмотр", "Управление", "Сообщение 'ПОРА РАБОТАТЬ!'", назови кнопки B_GetScr, B_Watch, B_Control, B_Message соответственно. -TCheckBox с текстом "Полноэкранный режим". -2 TTimer - 1 будет использоваться для работы в режиме просмотра удаленного рабочего стола, а второй для работы в режиме управления, у обоих компонентов установи свойство Enabled в False, а свойство Interval равным 400, это частота обновления картинки экрана сервера и посылки серверу команд, заданная в миллисекундах. -TImage - в нем будет отображаться картинка с удаленного рабочего стола.
Приступаем к коддингу. Для кнопки "Скриншот" создай обработчик OnClick и заряди в него код из листинга 2. procedure TForm1.B_GetScrClick(Sender: TObject); var s:TFileStream; Bitmap: TBitmap; PNG: TPNGObject; begin //Подключаемся к серверу connect_to_server; //Посылаем серверу команду "get_screen " IdTCPClient1.WriteLn('get_screen '); with IdTCPClient1 do begin if FileExists('C:\s.png') then DeleteFile('C:\s.png'); //Создаем поток s := TFileStream.Create('C:\s.png',fmCreate); //Пока есть соединение читаем данные while connected do ReadStream(s,-1,true); //Уничтожаем поток FreeAndNil(s); //Отключаемся Disconnect; Image1.Picture:=nil; //Выводим полученный скриншот на экран PNG := TPNGObject.Create; Bitmap := TBitmap.Create; try PNG.LoadFromFile('C:\s.png'); Bitmap.Assign(PNG); Image1.Picture.Bitmap.Assign(Bitmap); finally PNG.Free; Bitmap.Free; end; end; //end - with end;
Как видишь тут все достаточно элементарно. С помощью собственной процедуры connect_to_server (ее реализацию ты можешь найти в исходниках программы, расположенной на компакт диске), мы подключаемся к серверу. Для этого вызывается метод Connect компонента TidTCPClient, и предварительно устанавливаются свойства Host и Port. Затем с помощью процедуры WriteLn мы отправляем серверу команду "get_screen" после чего в ответ получаем графический файл формата PNG, который сохраняем на диске C: и отображаем его пользователю посредством компонента TImage. Реализацию остальных функций ты найдешь в исходниках программы, а сейчас давай просто погорим о том, как она осуществлена. При нажатии на кнопку "Просмотр", ее текст меняет на "Отключить просмотр", а кнопки "Скриншот" и "Управление" блокируются. Далее включается таймер, который через определенные промежутки времени, я установил значение 400 мс, обращается к серверу с просьбой прислать скриншот. Если пользователь нажимает на кнопку повторно, то режим просмотра отключается. Аналогично работает и режим управление, только клиент помимо запроса прислать скриншот отправляет координаты курсора мыши (сообщения "mouse_move ", "mouse_x" и "mouse_y "), полученные с помощью функции GetCursorPos, которые затем и устанавливаются у получателя. Если пользователь нажимает на кнопку "Сообщение 'Пора работать!'", то на сервер уходит команда "message_for_you ", которая приводит к вызову функции MessageBox и выводу поверх всех открытых окон текстового сообщения.
Итак, программа разработана, пора испытывать ее в боевых условиях, только сразу предупрежу, если у тебя стоит Firewall то настрой его таким способом, чтобы был возможен обмен сообщениями между двумя компьютерами сети по определенном порту (у меня выбран 6666).
Несколько слов напоследок Конечно эта утилита не само совершенство, так это и логично, ведь за совершенство просят деньги:):). Все в твоих руках, ты запросто можешь сделать из нее более серьезный продукт, реализовав дополнительные функции и возможности. Во первых наверняка сразу бросается проблема мерцания, при обновлении картинок, ее можно решить несколько изменив алгоритм работы получения скриншотов: для этого посылай не сами картинки, а лишь изменения между ними, если тебе покажется это сложно в реализации, то можно попробовать более простой вариант, когда после получения первого скриншота клиент со всех последующих сверяет то, что изменилось в следующем и отрисовывает эти изменения на картинке загруженной в TImage. Стоит отметить тот факт, что при разности в разрешениях экрана монитора на которых работает клиент и сервер, может наблюдаться эффект отставания курсора мыши, т.е. когда на своем мониторе вы наводите курсор на одно место, а на скриншоте присланном с удаленного компьютера он отстает и располагается чуть выше - решается это проблема вводом специального коэффициент и применением его к координатам передаваемых на сервер, тем самым удастся избавиться от этого минуса. Можно реализовать функцию работы по паролю, т.е. удаленно к тебе не могут подключиться не зная кодового слова. Про скрытие программы в трей, придание ей невидимости я говорить не буду, так как это классика жанра:):). А вот управление компьютером посредством ICQ, это поистине круто. Представь только! Тебе вообще не нужно вдаваться в тонкости сетевых технологий и протоколов передачи данных. Ты просто встраиваешь в свой сервер возможность приема и отправки ICQ-сообщний (благо дело в сети можно найти компоненты помогающие реализовать это без особых хлопот), и управляешь удаленно компьютером из любой точки мира. Фантазируй, экспериментируй и воплощай свои идеи. А если у тебя появится свободная минутка, можешь черкнуть пару своих мыслей мне на мыло, и возможно они найдут отражение в следующих выпусках Хакера. Конечно же без тени смущения пиши мне на ShkrylAndrei@rambler.ru, если с программой вдруг по какой-то необъяснимой причине возникнут сложности, только не забудь сначала заглянуть на диск и сверить находящиеся там исходники с тем, что накодировал ты.
рис. 3
Листинг 4 IdTCPServer1.Bindings.Add;
IdTCPServer1.Bindings.Items[0].IP:=IPadress.Text; IdTCPServer1.Bindings.Items[0].Port:=StrToInt(PortNumber.Text); IdTCPServer1.Active:=true;
На заметку Indy представляет собой набор классов Object Pascal для работы с сетью (в частности Интернет). Например, класс TIdTCPConnection предоставляет базовые функции для низкоуровневой работы с сетевыми сервисами. Одним из главных достоинств Indy является встроенный механизм многопоточности (multi-threading). Стоит отметить что компоненты Indy входят в комплект поставки Delphi и очень просты в использовании, например, ты можешь запросто создать FTP сервер или почтовый клиент, при этом написав минимум кода и не вникая в технологию реализации сетевых протоколов.
Еще одна заметка В 1978 году израильские исследователи Яков Зив (Jacob Ziv) и Абрам Лемпел (Abraham Lempel) изобрели новый алгоритм компрессии данных без потерь, названный LZ78. Публикация алгоритма была открытой, любой человек мог взять и использовать его для своих целей, поэтому в 1987 году сотрудник компании CompuServe Боб Берри (Bob Berry) разработал на основе LZW новый формат хранения изображений - Graphic Interchange Format (GIF). В декабре 1994 года было объявлено, что за использование алгоритма LZ78 нужно выплачивать лицензионные отчисления разработчикам, таким образом, использование формата GIF стало платным. После этого была создана рабочая группа под руководством Томаса Боутела (Thomas Boutell), которая решала задачу по разработке альтернативы GIF. Что в дальнейшем и было сделано, новый формат получил название PNG (Portable Network Graphics). Исходники примера ищи в архиве: radmin.rar
By Андрей Шкрыль aka LittleBudda E-Mail: shkrylandrei@rambler.ru
Подкачку - под контроль! Вообще, в 32-разрядной Windows под памятью понимают не только оперативку, но и память, резервируемую операционной системой на жёстком диске (файл подкачки). Код и данные отображаются на жесткий диск с помощью страничной системы (paging system) подкачки. Страничная система использует для отображения страничный файл (pagefile.sys в Windows NT и, если мне не изменяет память, win386.swp в Windows 95/98). Нужный кусок виртуальной памяти переносится из страничного файла в ОЗУ и, таким образом, становится доступным. А если таким макаром создовать любой другой файл и сделать его куском адрессного пространства? В Win32 это возможно. Для выделения фрагмента памяти должен быть создан специальный системный объект Win32, называемый отображаемым файлом. Посредством этого объекта просиходит соотношения файла, находящегося на жестком диске, с памятью, адресуемой процессами. Приложения могут открывать отображаемый файл и получать доступ к данным этого объекта. Т.е. данные, помещённые в страничный файл, могут быть доступны другим приложениям, если они открыли и используют тот же отображаемый файл. Итак, значит у нас есть два варианта - либо создать свой собственный файл подкачки, либо использовать уже существующий, например, файл подкачки вЕнды. В каких-то случаях будет удобнее и практичнее создать свой страничный файл, но в каких-то лучше использовать уже готовый. Разницей в реализации этих способов будет лишь изменение параметра одной из используемых функций. Теперь давай разбираться с функциями, которые дают нам возможность работы с файлами подкачки. Это, естественно, функции WinAPI и их три: 1.CreateFileMapping 2.MapViewOfFile 3.UnMapViewOfFile Отображаемый файл создается операционной системой при вызове функции CreateFileMapping. Этот объект поддерживает соответствие между содержимым файла и адресным пространством процесса, использующего этот файл. Функция CreateFiieMapping (hFile: THandle; IpFileMappingAttributes: PSecurityAttributes; flProtect, dwMaximumSizeHigh, dwMaximumSizeLow: DWORD; IpName: PChar): THandle; имеет шесть параметров: hFile: THandle - он должен соответствовать хендлу уже открытого файла. IpFileMappingAttributes: PSecurityAttributes - указатель на запись типа TSecurityAttributes. При отсутствии требований к защите данных в Windows NT этот параметр всегда равен nil. flProtect: DWORD - определяет атрибут защиты. Т.к. мы планируем совместное (ОС и прога) использование данных, то нам будет достаточно значения PAGE_READWRITE. dwMaximumSizeHigh, dwMaximumSizeLow: DWORD - Когда выполняется функция CreateFiieMapping, то, проще говоря, эти значения объединяются в одно 64-разрядное число, равное объему памяти, выделяемой объекту файлового отображения из страничного файла
операционной системы. Мы хотим отобразить весь файл, значит четвертый и пятый параметры должны быть равны нулю. IpName: PChar - имя объекта файлового отображения. Функция CreateFileMapping возвращает значение типа THandle. В случае успешного завершения возвращаемое функцией значение равно дескриптору созданного объекта файлового отображения. В случае возникновения какой-либо ошибки возвращаемое значение будет равно 0. Теперь надо спроецировать данные файла в адресное пространство нашего процесса. Для этого нужно заюзать функцию function MapViewOfFile(hFileMappingObject: THandle; dwDesiredAccess: DWORD; dwFileOffsetHigh, dwFileOffsetLow, dwNumberOfBytesToMap: DWORD):Pointer; Она имеет пять параметров: hFileMappingObject: THandle - этим значением должен быть дескриптор созданного объекта файлового отображения, который возвращает функция createFileMapping. dwDesiredAccess: DWORD - этот параметр определяет режим доступа к файлу. Может быть равным: FILE_MAP_WRITE, FILE_MAP_READ или FILE_MAP_ALL_ACCESS. dwFileOffsetHigh, dwFileOffsetLow: DWORD - смещение отображаемого участка относительно начала файла в байтах. Ставь их равными нулю (это потому, что последний параметр так же будет равен нулю, см. ниже). dwNumberOfBytesToMap: DWORD - используется для определения (в байтах) количества данных файла подкачки, которые надо сделать доступными для нас. Если выставить этот параметр в ноль, то в процессе автоматически отоброзятся все данные, выделенные перед этим функцией CreateFileMapping. Если функция MapViewOfFile отработала успешно, то она вернет начальный адрес данных объекта файлового отображения. Теперь давай попробуем накотать какой-нить пример: var hMappedFile: THandle; pSharedBuf: PChar; begin //создаём отображаемый файл hMappedFile:=CreateFileMapping (FHandle,nil,PAGE_READWRITE,0,0,'SharedBlock'); if (hMappedFile = 0) then ShowMessage('Mapping error!') else begin //проецируем данные файла в адресное пространство pSharedBuf:=MapViewOfFile(hMappedFile, FILE_MAP_ALL_ACCESS, 0, 0, 0) ; if (pSharedBuf = nil) then ShowMessage ('MapView error'); end; end;
После того как получен указатель pSharedBuf, мы можем работать со своим файлом как с обычной областью памяти, не заботясь о вводе, выводе, позиционировании и т.п. Все эти проблемы берет на себя файловая система. Последняя функция, имеющая отношение к объекту файлового отображения, называется UnMapViewOfFile. Функция UnMapViewOfFile прекращает отображение в адресное пространство процесса того файла, который перед этим
был отображен При помощи функции MapViewOfFile. Ну а Функцией CloseHandle закрываем дескриптор объекта файлового отображения. Сделаем это, например, при разрушении формы: procedure TForm1.FormDestroy(Sender: TObject); begin //чистим за собой UnMapViewOfFile(pSharedBuf); CloseHandle(hMappedFile); end;
Вот в принципе и всё! Главное не забывай освобождать после себя память. И очень внимательно проверяй все параметры функций. Допустишь ошибку - всё, прога не работает!
by Soffrick www.Liveofpc.3dn.ru e-mail: Soffrick@mail.ru
Потоки и планирование выполнения В Windows у каждого процесса есть адресное пространство и один поток. Однако в некоторых приложениях желательно иметь несколько потоков, параллельно (или псевдопараллельно) выполняющихся в одном адресном пространстве. Одним из таких приложений является веб-браузер. Большинство веб-страниц содержат множество картинок небольшого размера. Для получения каждой картинки необходимо установить отдельное соединение с сайтом, которому принадлежит страница, и получить запрашиваемую картинку. Поскольку установка и разрыв соединений отнимают много времени по сравнению с передачей небольших картинок, имеет смысл загружать несколько картинок одновременно для ускорения загрузки страницы. Теперь совершим краткий экскурс в теорию. Как и процессы, потоки могут находиться в одном из следующих состояний: выполнения, готовности и блокировки. Ниже приведена диаграмма состояний и возможных переходов между ними. Выполнение
Блокировка
Готовность
Поток находится в состоянии выполнения, если он выполняется процессором. В многопроцессорных системах одновременно могут выполняться несколько потоков. Планировщик переводит поток в состояние блокировки, если он выполняет функцию ожидания таких объектов, как процессы, потоки, входные данные. Поток находится в состоянии готовности, если он может выполняться. Когда процессор станет доступным, планировщик запустит тот из потоков, находящихся в состоянии готовности, который имеет наивысший приоритет, а при наличии нескольких таких потоков тот, который пребывал в состоянии готовности дольше всех. Хочется обратить внимание на то, что программист может распределять процессоры между потоками с помощью функций SetProcessAffinityMask, GetProcessAffinityMask и SetThreadIdealProcessor. После истечения времени, отведенного выполняющемуся потоку (обычно несколько десятков миллисекунд), планировщик переводит его в состояние готовности. Теперь наша теоретическая подготовка находится на должном уровне, и мы можем перейти к нужному нам языку программирования (в данном случае это будет Delphi). Хочу заметить, что я не буду приводить здесь исчерпывающего описания функций, так как лучше, чем это сделано в MSDN, мне не написать, но буду давать описание, достаточно полное для понимания назначения функции. В связи с этим я настоятельно рекомендую в дополнение к этой статье внимательно прочитать то, что написано в MSDN о каждой из упомянутых мною функций. Для создания потока в Delphi есть специальная функция, имеющая следующий прототип:
function CreateThread(lpThreadAttributes: Pointer; dwStackSize: Cardinal; lpStartAddress: Pointer; lpParameter: Pointer; dwCreationFlags: Cardinal; var lpThreadIs: Cardinal): Cardinal;
Рассмотрим ее параметры: •
lpThreadAttributes – указатель на структуру атрибутов защиты, ставим nil (по
• •
dwStackSize – размер стека нового потока в байтах, ставим 0 (по умолчанию); lpStartAddress – указатель на функцию, которая должна выполняться в потоке и иметь
умолчанию); такую сигнатуру:
•
• • •
function <имя_функции>(<имя_параметра>: Pointer): Cardinal; stdcall; lpParameter – указатель, передаваемый в функцию в качестве аргумента; dwCreationFlags – либо 0 (поток сразу запускается), либо CREATE_SUSPENDED (приостановлен, запуск через ResumeThread); lpThreadId – в переменную записывается глобальный идентификатор нового потока.
Функция возвращает дескриптор потока или 0 в случае ошибки. Любой поток может завершить свое выполнение: procedure ExitThread(dwExitCode: Cardinal). Также выполнение потока можно завершить другим потоком с помощью функции function TerminateThread(hThread: THandle; dwExitCode: Cardinal): LongBool (но лучше так не делать). Поток, выполнение которого было завершено, существует до тех пор, пока посредством функции function CloseHandle(hObject: Cardinal): LongBool; не будет закрыт ее последний дескриптор. Любой другой поток может получить код завершения данного потока procedure GetExitCodeThread(hThread: Cardinal; var lpExitCode: Cardinal). Если поток не завершен, то в lpExitCode будет значение STILL_ACTIVE. Теперь рассмотрим функции идентификации потоков: • •
function GetCurrentThread: Cardinal – возвращает дескриптор текущего потока; function GetCurrentThreadId: Cardinal – возвращает идентификатор текущего
потока.
У каждого потока есть свой счетчик приостановок. Поток будет выполняться только в случае равенства этого счетчика нулю. Для изменения этого счетчика используются следующие функции, возвращающие предыдущее значение счетчика: • •
function ResumeThread(hThread: Cardinal): Cardinal – уменьшение счетчика; function SuspendThread(hThread: Cardinal): Cardinal – увеличение счетчика.
Поток может дожидаться завершения выполнения другого потока (других потоков) с помощью следующих функций ожидания: • •
function WaitForSingleObject(hHandle: Cardinal; dwMilliseconds: Cardinal): Cardinal; function WaitForMultipleObjects(nCount: Cardinal; lpHandles: PWOHandleArray; bWaitAll: Boolean; dwMilliseconds: Cardinal): Cardinal.
Аргументы этих функций: • дескриптор одиночного потока (hHandle), либо дескрипторы ряда потоков, хранящиеся в массиве размерностью nCount, на который указывает lpHandles; • dwMilliseconds – число миллисекунд интервала ожидания;
•
bWaitAll – если значение равно True, то ожидается завершение выполнения всех
потоков, а не только одного.
Функции могут возвращать следующие значения: • WAIT_OBJECT_0 – указанный поток завершил свое выполнение (WaitForSingleObject) или одновременно все потоки завершили свое выполнение (WaitForMultipleObjects при bWaitAll = True); • WAIT_OBJECT_0 + N – здесь N (0 ≤ N ≤ nCount-1) - индекс потока, завершившего свое выполнение; • WAIT_TIMEOUT – в течение заданного времени ни один поток не завершил свое выполнение; • WAIT_FAILED – неудачное завершение функции; • WAIT_ABANDONED_0 – сейчас не рассматриваем. Теперь пусть перед нами стоит задача написания консольной программы, осуществляющей поиск слова ‘Moderator’ в нескольких текстовых файлах, имена которых передаются в качестве входных параметров. В данном случае очень желательно для каждого файла создать отдельный поток, выполняющий поиск в данном файле. Это даст выигрыш в производительности, так как в многопроцессорных системах потоки выполняются параллельно на различных процессорах, и при использовании нескольких дисков операции ввода/вывода с участием нескольких файлов будут осуществляться в параллельном режиме. Исходный код программы с подробными комментариями к журналу прилагается. А сейчас рассмотрим еще одну возможность управления потоками, не использованную в данной программе, а именно расстановку приоритетов. Как уже выше упоминалось, ядро ОС всегда запускает тот из потоков, готовых к выполнению, который обладает наивысшим приоритетом. Во время создания потока его приоритет устанавливается равным приоритету процесса, который, в свою очередь, может принимать следующие значения: • IDLE_PRIORITY_CLASS, базовый приоритет 4; • NORMAL_PRIORITY_CLASS, базовый приоритет 9 (фокус ввода с клавиатуры находится в окне) или 7; • HIGH_PRIORITY_CLASS, базовый приоритет 13; • REALTIME_PRIORITY_CLASS, базовый приоритет 24. Получить и изменить приоритет процесса можно с помощью функций GetPriorityClass и SetPriorityClass. Приоритеты же потоков получаются и изменяются с помощью функций GetThreadPriority и SetThreadPriority. Приоритеты потоков могут принимать значения в интервале ±2 относительно базового приоритета процесса: THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_BELOW_NORMAL,THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_ABOVE_NORMAL, THREAD_PRIORITY_HIGHEST. Однако существуют и два абсолютных значения приоритета потоков: THREAD_PRIORITY_IDLE (приоритет 1), THREAD_PRIORITY_TIME_CRITICAL (приоритет
15). И напоследок одна фраза о всем известной процедуре Sleep. Эта процедура позволяет потоку отказаться от процессора и перейти из состояния выполнения в состояние блокировки, которое будет длиться в течение заданного промежутка времени, после чего поток перейдет в состояние готовности. Исходники примера ищи в архиве: threads.rar
by Darvin E-mail: darvin89@inbox.ru
Разработка многопоточных приложений Если задачи приложения можно разделить на различные подмножества: обработка событий, ввод / вывод, связь и др., то потоки могут быть органично встроены в программное решение. Сделав приложение многопоточным, программист получает дополнительные возможности управления им: 1. Если один из потоков “притормаживает” приложение, занимая слишком много процессорного времени, то можно понижают приоритет этого потока; 2. При возрастании “нагрузки” на приложение можно увеличить количество потоков; 3. При добавлении нового клиента (случай клиент-серверных приложений) сервер может запустить специально для этого отдельный поток. Потоки бывают: 1. Симметричные
(symmetric
threads)
–
потоки,
выполняющие
одинаковое
предназначение, исполняющие одни и тот же код и в большинстве случаев разделяющие одни и те же ресурсы; 2. Ассиметричные (asymmetric threads) – потоки, которые решают различные задачи и, как правило, не разделяющие совместные ресурсы. Ассиметричные потоки необходимо использовать, когда: 1. в программе необходимы длительные вычисления, при этом необходимо сохранить нормальную реакцию на ввод; 2. нужно обрабатывать асинхронный ввод/вывод с использованием различных устройств (COM – порта, звуковой карты, принтера и т. д.); 3. необходимо создать несколько окон и одновременно обрабатывать ввод в них. Использование потоков вместо процессов в рамках одного приложения: 1. Минимизирует затраты на переключение “параллельно” выполняющимися задачами; 2. Поскольку процессы используют раздельные ресурсы, то возникает проблема их разделения. Потоки уже по своей природе разделяют ресурсы.
Фоновые процедуры внутри одной программы Цикл обработки сообщений – это особый фрагмент кода в программе, управляемой событиями. Он исполняется, когда программа находит в очереди к события, которые нужно обработать; если таковых нет, программа выполняет “фоновую процедуру”. Отрицательные черты такого подхода: 1. необходимо сохранять состояние фоновой процедуры между ее вызовами; 2. определять момент, когда она вернет управление обработчику событий.
Приоитеты потоков Приоритет потока – величина, складывающаяся из двух составных частей: 1. приоритета породившего поток процесса; 2. приоритета потока.
КЛАССЫ ПРИОРИТЕТОВ ПРОЦЕССОВ 1. REAL TIME Задает приоритет даже больший чем у многих процессов операционной системы. Такой приоритет нужен для процессов, обрабатывающих высокоскоростные потоки данных. Если такой процесс не завершится в короткое время, пользователь почувствует, что система перестала откликаться.
2. HIGH Устанавливает приоритет процессам, которые должны завершаться за короткое время, чтобы не вызвать сбойной ситуации (например, процесс посылает сигналы внешнему устройству, причем устройство отключается, если не получает своевременный сигнал). Влияет на всю систему, поэтому не целесообразно за счет этого повышать производительность пользовательского приложения. 3. ABOVE NORMAL (не рассматривается) 4. NORMAL Задает приоритет, который показывает, что процесс не требует какого-то специального внимания со стороны операционной системы. 5. BELOW NORMAL (не рассматривается) 6. IDLE
Задает приоритет для процессов, которые запускаются в случае, если в очереди диспетчера задач нет других процессов (например, программы сохранения экрана, системные агенты). Класс целесообразно задавать для организации завершающих операций и реорганизации данных (сохранение документа, копирование базы данных). Базовый приоритет нити складывается из двух составляющих (Таблица 1) Таблица 1 – Классы процессов и приоритеты их потоков (Windows 2000, XP). IDLE_PRIORITY_ CLASS
BELOW_NORMAL_ PRIORITY_CLASS
NORMAL_ PRIORITY_ CLASS
ABOVE_ NORMAL_ PRIORITY_ CLASS
HIGH_ PRIORITY_ CLASS
REALTIME_ PRIORITY_ CLASS
1
1
1
1
1
16
2
4
8
11
22
3
5
9
12
23
4
6
10
13
24
5
7
11
14
25
6
8
12
15
26
15
15
15
15
31
THREAD_ PRIORITY_ IDLE THREAD_ PRIORITY_ LOWEST
5(B) 7(F)
THREAD_ PRIORITY_ BELOW_
6(B) 8(F)
NORMAL THREAD_ PRIORITY_ NORMAL
7(B) 9(F)
THREAD_ PRIORITY_ ABOVE_
8(B) 10(F)
NORMAL THREAD_ PRIORITY_ HIGHEST
9(B) 11(F)
THREAD_ PRIORITY_ TIME_
15
CRITICAL
Процессы, имеющие класс NORMAL_PRIORITY_CLASS, могут выполняться в двух режимах: •
фоновый режим (Background);
•
режим приложений (Foreground),
Планировщик назначает динамический приоритет для NORMAL_PRIORITY_CLASS, имеющий два значения. Windows NT и более поздние ОС на этом ядре позволяют переключать режим оптимизации (Рисунок 1)
Рисунок 1 – Утилита настройки параметров быстродействия
Особенности алгоритмов выделения квантов времени: •
Windows 2000 Professional (Клиентская операционная система);
Выделяет время короткими квантами переменной длины для ускорения реакции на приложения переднего плана (Foreground); •
Windows 2000 Server (Серверная операционная система).
В этом случае наиболее важна стабильная работа системных служб, и как следствие этого, ОС система распределяет длинные кванты постоянной длины. Назначение потоку, обрабатывающему ввод, более высокого приоритета, а всем остальным – более низкого или даже приоритета idle, если поток должен выполняться только во время простоя системы.
Класс TThread
С точки зрения ОС поток – ее объект. Для разработки многопоточных приложений в среде Borland Delphi предусмотрен класс TThread. Объект класса TThread: •
это конструкция Dephi, которая соответствует потоку ОС;
•
создается до реального возникновения потока;
•
уничтожается после исчезновения потока.
1. Метод Execute Таблица 2 – Класс TThread Метод
Синтаксис
Описание
Procedure Execute; virtual; Код, который создается и abstract; исполняется в создаваемом
Execute
потоке Особенности использования метода Execute 1. Мастер создания объекта TThread формирует пустой шаблон этого метода 2. Если поток рассчитан на однократное выполнение каких-либо действий, то никакого специального кода завершения внутри Execute писать не надо. 3. Если в потоке будет выполняться цикл и поток должен завершиться вместе с приложением, то условия окончания должны быть особо сформированы, например: Procedure TMyThread.Execute; Begin Repeat code Until (Условие выхода) or Terminated End;
Условие выхода – условие разработчика Terminated – свойство завершения потока 2. Конструктор объекта Create Конструктор Create
Синтаксис Constructor Create Создание (CreateSuspended: Boolean) TThread
Особенности использования конструктора
Описание объекта
класса
1. Если значение передаваемого в конструктор параметра CreateSuspended равно True, вновь созданный поток не начнет выполняться до тех пор, пока не будет сделан вызов метода Resume. 2. Если значение передаваемого в конструктор параметра CreateSuspended равно False, поток выпоняется сразу после завершения работы конструктора 2. Деструктор объекта Destroy Деструктор Destroy
Синтаксис Destructor Destroy; override;
Описание Завершает
поток
высвобождает
все
и
ресурсы,
связанные с объектом типа TThread 3. Метод Terminate Метод Terminate
Синтаксис function Terminate: integer;
Описание Устанавливает
свойство
Terminated, что дает указание потоку
завершиться,
возможностью
с
корректно
освободить ресурсы.
Метод Terminate автоматически вызывается из деструктора объекта. Поток – объект VCL будет дожидаться, пока завершится поток – объект операционной системы. Если поток не умеет завершать корректно, то вызов деструктора может привести к зависанию всей программы. 4. Свойство FreeOnTerminate Свойство FreeOnTerminate
Синтаксис Property Boolean;
Описание
FreeOnTerminate: Если установлено в True, то деструктор будет
автоматически вызван
завершения потока.
после
Целесообразно использовать в случаях, когда не известны условия завершения потока 5. Функция WaitFor: Integer; Функция
Синтаксис
WaitFor
Описание
Function WaitFor: Integer;
Синхронизирует
работу
потоков
одному
потоку
(позволяет дождаться
момента
завершения другого потока) Особенности: 1. Если внутри потока FirstThread написать код: Code := SecondThread.WaitFor;
то это означает, что поток FirstThread останавливается до момента завершения потока SecondThread; 2. Метод WaitFor возвращает код завершения ожидаемого потока в свойство ReturnValue (property ReturnValue: integer), которое по умолчанию равно 0, но может быть использовано
программистом для своих нужд, например, при отладке потока
(возвращение каких либо параметров) 6. Свойства Handle и ThreaID Свойство
Синтаксис
Handle
Property Handle:
ThreadID
read FHandle
Описание THandle Обеспечивают непосредственный
доступ
к
потоку средствами API Win32 Property ThreadID: THandle read FThreadID
1. Могут быть использованы в качестве аргументов функций Win32; 2. Используются при работе с потоками минуя класс TThread (например, если перед продолжением выполнения приложения необходимо дождаться завершения сразу нескольких потоков, то можно вызвать API функцию WaitForMultipleObjects и в качестве входных параметров передать массив дескрипторов потоков) 7. Свойство Priority
Свойство Priority
Синтаксис
Описание Priority: Позволяет
Property TThreadPriority;
запросить
и
установить приоритет потоков (см. выше)
Допустимые значения: tpIdle, tpLowest, tpLower, tpNormal, tpHigher, tpHighest, tpTimeCritical 8. Метод Synchronize Свойство Synchronize
Синтаксис
Описание
Procedure
Используется для безопасного
Synchronize(Method:
вызова методов VCL внутри
TThreadMethod)
потоков.
1. Аргумент, передаваемый в метод Synchronize дает гарантию, что каждому объекту VCL одновременно имеет доступ 1 поток; 2. Передаваемый метод класса TThreadMethod не должен иметь никаких параметров и не должен возвращать никаких значений. Например, в основной форме приложения нужно предусмотреть функцию Procedure TMainForm.SyncShowMessage; Begin ShowMessage(IntToStr(ThreadList1.Count)); End;
а в потоке писать ShowMessage(MainForm.SyncShowMessage); Остальные процедуры и функции 1. procedure Resume •
Вызывается при возобновлении потока после остановки
•
Вызывается для явного запуска потока, созданного с параметром CreateSuspended = True
2. procedure Suspend
•
Вызов Suspend приостанавливает поток с возможностью повторного запуска впоследствии
•
Приостанавливает поток вне зависимости от кода, исполняемого потоком в данный момент
Исходный текст примера ты можешь посмотреть в файле threads.txt
Селиванов Константин aka KeyWareZ E-mail: KeyWareZ@yandex.ru ICQ 497272275
Базы данных
Работа с Oracle. Часть 3 Работа с Oracle. Часть 4
Работа с Oracle. Часть 3 В этой статье я покажу как настроить печать из приложения с помощью системы Rave Reports. Ведь без печатных форм документов наша система теряет смысл существования, получается что есть входящяя информация, которую вводят посредством экранных форм, но нет выходящей. Таким образом, система перестаёт выполнять свою функцию. Итак, продолжаем модернизировать разработанную нами в предыдущих статьях миниинформационную систему. В выходящей документации информация чаще всего группируется, суммируется, такая документация носит аналитический характер, и предназначена в основном для руководителей. Для реализации данной функции (аналитики), используются SQL- запросы. Формирование запросов возможно выполнять либо в клиентской части информационной системы (т.е. в самом приложении), либо в серверной (на сервере Oracle, где находится база данных). Как сказал один умный человек – Я предпочитаю решать большинство проблем на уровне СУБД. Если что-то можно сделать в СУБД, я так и сделаю. Для этого есть две причины. Первая и главная состоит в том, что если встроить функциональность в СУБД, то ее можно будет применять где угодно. Я не знаю серверной операционной системы, для которой нет реализации СУБД Oracle. Одна и та же СУБД Oracle со всеми опциями работает везде — от Windows до десятков версий ОС UNIX и больших ЭВМ типа OS/390. Таким образом, формирование SQL-запросов будем выполнять в базе данных на сервере посредством уже знакомых нам представлений. Правда есть ещё и другие варианты размещения запросов (например, распределённые системы), но их рассмотрение выходит за границы данной статьи. Прежде чем начинать разработку отчётов нам необходимо определиться какого рода информацию нам необходимо получить в выходящей документации и в каком виде. Для начала мы реализуем печать информации по заказу, а затем получение сводного отчёта с разбивкой по заказчикам. Говоря своими словами, мы сможем распечатать информацию по сформированному заказу (например, для предоставления заказчику, как прайс-лист в магазине), а также распечатать отчёт, в котором показано в разрезе каждого заказчика что он заказал и в каком количестве (ну это для начальника). Для этого нам опять же необходимо обратиться к нашей базе (а как же без этого ). Необходимо создать представления следующего вида: Для печати заказа: CREATE OR REPLACE VIEW ZAKAZ_REPORT AS SELECT zakaz.nomer, zakaz.DATA, klient.naimen klient, klient.adres, klient.fax, klient.tel, zakaz.id_zak FROM zakaz, klient WHERE ((klient.id_kl = zakaz.id_kl));
Структура данного запроса такая:
Здесь отмечу только переименование столбца klient.naimen klient, т.е. в представлении он будет называться klient. CREATE OR REPLACE VIEW POS_ZAK_REPORT AS SELECT pos_zakaza.id_zak, pos_zakaza.kolvo, izdelie.charact FROM pos_zakaza, izdelie WHERE ((izdelie.id_izd = pos_zakaza.id_izd));
izdelie.naimen
izdelie,
Структура данного запроса такая:
Для печати сводного отчёта: CREATE OR REPLACE VIEW KLIENT_SVOD AS SELECT Distinct klient.naimen, klient.id_kl FROM klient WHERE EXISTS (Select * from zakaz where klient.id_kl=zakaz.id_kl); Здесь конструкция Distinct означает отбор неповоторяющихся значений, ну конечно, ведь если заказчик сделает два или три заказа, то запрос отберёт его так же два или три раза, как будто это три разных заказчика. А также в условии отбора конструкция Exists помогает отобрать только тех клиентов, для которых создан заказ. CREATE OR REPLACE VIEW POS_ZAK_SVOD AS SELECT SUM (pos_zakaza.kolvo) kolvo, pos_zakaza.id_zak, izdelie.naimen, izdelie.charact FROM pos_zakaza, izdelie WHERE ((izdelie.id_izd = pos_zakaza.id_izd)) GROUP BY pos_zakaza.id_zak, izdelie.naimen, izdelie.charact; Структура данного запроса полностью соответствует предыдущему. Здесь переименовывается столбец, в котором идёт суммирование количества заказанных изделий SUM (pos_zakaza.kolvo) kolvo. В данном представлении выполняется группировка по столбцам pos_zakaza.id_zak, izdelie.naimen, izdelie.charact, т.е. происходит суммирование значения Количества изделий по Заказу, Изделию, Характеристике изделия. Изменения с базой закончены, теперь приступаем к доработке приложения. Сначала добавим в приложение компоненты для доступа к нашим представлениям. Здесь возможны два варианта: использовать Table’ы, или использовать Query. При работе с локальными базами данных чаще используется Table. С его помощью проще не только просматривать таблицу базы данных, но и модифицировать записи, удалять их, вставлять новые записи. Но при работе с серверными базами данных компонент Table становится мало эффективным. В этом случае он создаёт на компьютере пользователя временную копию серверной базы данных и работает с этой копией. Естественно, что подобная процедура требует больших ресурсов и существенно загружает сеть.
Этот недостаток отсутствует в компоненте Query. Если запрос SQL сводится к просмотру таблицы (запрос Select), то результат этого запроса (а не сама исходная таблица) помещается во временном файле на компьютере пользователя. Благодаря такой организации работы эффективность Query при работе в сети становится много выше, чем эффективность Table. Таким образом наш выбор остановится на Query, а в приложении мы лишь установим фильтр, который можно реализовать добавив в теле запроса условие отбора. Итак, добавляем четыре компонента Query с закладки BDE, устанавливаем их свойство DatabaseName (имя нашей базы). У меня получилось соответственно четыре Query: Zakaz_report, Pos_zak_report, Klient_svod и Pos_zak_svod. Теперь необходимо прописать в свойстве SQL каждого из компонентов запрос к базе данных - получение данных созданных нами ранее представлений. Для Zakaz_report: Select * from ZAKAZ_REPORT Where ID_ZAK=:id_zak Здесь :id_zak – это параметр, т.е. это значение столбца ID_ZAK в представлении ZAKAZ_REPORT которое нас интересует, а интересовать нас будет текущее значение столбца ID_ZAK Table’а Zakaz, т.е. значение ID_ZAK текущей строки в таблице Заказов, ведь печать мы будем делать из журнала заказов, для получения отчёта по выбранному заказу. Для Pos_zak_report: Select * from POS_ZAK_REPORT Where ID_ZAK=:id_zak Здесь :id_zak – также параметр, значение столбца ID_ZAK Table’а Zakaz. Т.е. будут отобраны все строки для выбранного заказа. Для Klient_svod: Select * from KLIENT_SVOD Без комментариев. Для Pos_zak_svod: Select * from POS_ZAK_SVOD Здесь я думаю тоже всё понятно. Теперь необходимо у всех Query зайти в свойство Params (кнопка с тремя точками), и в свойстве DataType единственного параметра (см. выше) выбрать ftInteger, иначе будет ругаться на то что не определён тип параметра. После этого можно сохранить весь проект. Затем как обычно идём в редактор полей наших Query (двойной щелчок мышью), и добавляем все столбцы (Add all fields). Осталось добавить на главной форме кнопку Печать и подпункт меню Сводный отчёт пункта «печать», вот что получилось: Таким образом, если необходимо распечатать информацию по заказу (например, для заказчика), нажимаем кнопку Печать, если необходимо предоставить сводный отчёт по заказчикам (для начальника) – заходим в пункт меню Печать->Сводный отчёт.
Главная форма
Ну а теперь приступим к программированию печати. Схема печати отчёта по заказу будет выглядеть следующим образом: мы встаём на нужную позицию (заказ), нажимаем кнопку Печать, соответственно в Query Zakaz_report и Pos_zak_report будут загружаться соответствующие данные (не забываем про параметры), затем компоненты с закладки Rave будут передавать эти данные в отчёт. Соответственно для печати сводного отчёта схема та же. Для связи наших Query c отчётом добавим компонент RvProject с закладки Rave, четыре компонента RvQueryConnection и свяжем их с нашими Query (свойство Query у каждого RvQueryConnection), а также RvTableConnection для связи с Table’ом Zakaz (объясню позже). Далее запускаем редактор Rave Reports (Tools->Rave Reports Designer). Прежде чем начать работать с редактором, необходимо сохранить проект (File->Save As) в папку с приложением, я например, создал в папке с приложением папку reports и сохранил новый проект туда. Сохранять лучше всего в папку с приложением потому, что в компоненте RVProject в свойстве ProjectFile необходимо указать путь к файлу отчёта. Если например мы сохраним файл отчёта в каком-то другом месте (например C:\Documents and settings\...), при поставке приложения клиентам прийдётся позаботиться об указании пути к файлу отчёта, так как например у тебя система стоит на диске С, а у того кому ты поставляешь она установлена например на D, т.е. у того человека папки Documents and settings на диске С нет. Прописав же в свойстве ProjectFile компонента RVProject просто имя файла отчёта (по умолчанию Project1.rav) и сохранив его в папку с приложением ты создаёшь так называемый абсолютный путь к файлу отчёта. Теперь, при поставке приложения клиенту, тебе достаточно сам файл приложения и файл отчёта скопировать в одну папку, и приложение само найдёт этот файл (отчёт), так как при отсутствии пути к файлу, компонент RVProject в первую очередь ищет файл в папке с приложением. У меня в свойстве ProjectFile компонента RVProject прописано reports\Project1.rav, т.е. при
поставке клиенту нужно будет создать папку для приложения (например, C:\Журнал заказов\), а в ней создать папку reports и скопировать туда файл отчёта. Итак, приступаем к разработке отчёта. Первое что нам надо сделать, это связаться с компонентами Rave в приложении для получения данных. Для этого заходим в меню File->New data object (или пиктограмма на панели), в окне Data connections выбираем Direct data view, затем в списке Active data connections выбираем наши RVQueryConnection’ы (RVTableConnection’ы не забываем), можно через SHIFT, и нажимаем Finish. Всё связь настроена, теперь справа в дереве появилась новая ветка Data view dictionary, в которой ты можешь наблюдать наши DataView:
DataView1 связан с RVQueryConnection1 (представление ZAKAZ_REPORT), DataView2 связан с RVQuryConnection2 (представление POS_ZAK_REPORT), DataView3 связан с RVQueryConnection3 (представление POS_ZAK_SVOD), DataView4 связан с RVTableConnection1 (таблица ZAKAZ), DataView5 связан с RVQueryConnection4 (представление KLIENT_SVOD). Приступим к проектированию отчёта по заказу. Для этого добавим компонент Region с закладки Report, и растянем его на весь лист отчёта. Затем с этой же закладки добавим последовательно компоненты: два Band’а и DataBand. Первый бэнд у нас будет содержать атрибуты заказа (представление ZAKAZ_REPORT), второй будет играть роль шапки у позиций заказа, третий (DataBand) будет отображать строки позиций заказа. Не буду расписывать как добавлять компоненты, думаю вы и так поняли, выглядеть будет так:
Здесь поля с надписями это компонент Text с закладки Standart, поля с данными это компонент DataText с закладки Report. В свойстве каждого из DataText’а DataView установим DataView1 (представление ZAKAZ_REPORT), а в свойстве DataField – соответствующее поле (см. скриншот). Чтобы посмотреть что получилось, надо добавить следующий код при нажатии кнопки «Печать»: procedure TForm3.Button1Click(Sender: TObject); begin Zakaz_report.Close; Zakaz_report.ParamByName('id_zak').Value:=Form3.ZakazID_ZAK.Value; Zakaz_report.Open; Pos_zak_report.Close; Pos_zak_report.ParamByName('id_zak').Value:=Form3.ZakazID_ZAK.Value; Pos_zak_report.Open; RVProject1.Open; RVProject1.ExecuteReport('Report1'); RVProject1.Close; end;
Здесь для каждого Query указывается параметр, на основе которого идёт отбор данных (по столбцу ID_ZAK), а также открывается и запускается отчёт. Давайте ещё добавим компонент RVSystem с закладки Rave, и укажем в свойстве RVProject Engine данный компонент. Компонент RVSystem позволит нам управлять параметрами отчёта, установив например свойство DefaultDest в rdPrinter вместо rdPreview (по умолчанию), в окошке появляющемся перед печатью будет стоять пункт Printer вместо Preview, т.е. по умолчанию будет предлагаться распечатать отчёт вместо просмотра. А установив свойство SystemSetups->ssAllowSetup в false окошко диалога вообще не будет появляться, т.е. будет выполняться действие установленное в свойстве DefaultDest, например rdPreview – сразу просмотр отчёта. Теперь можете запустить приложение и встав на нужный заказ нажать кнопку Печать для просмотра отчёта, у меня получилось так:
Осталось только «нарисовать» печать позиций заказа, и наш отчёт будет готов. Возвращаемся к Rave Report. На втором бэнде рисуем шапку для позиций заказа, а на третьем (DataBand), симметрично шапке добавляем поля данных указав в свойстве DataView этих полей DataView2 (представление POS_ZAK_REPORT), а в свойстве DataField – соответствующее поле данных. В свойстве DataView DataBand’а укажите DataView2, затем заходим в Band Style editor данного DataBand’а (свойство BandStyle), и поставим галочку Detail(D) и NewPage(P). Ну и последний штрих – свойство BandStyle у первого бэнда ставим BodyHeader(B) (NewPage(P) не ставим), у второго бэнда (шапки) – BodyHeader(B), NewPage(P), чтобы шапка появлялась и на последующих страницах, а так же свойство ControllerBand у данного бэнда – DataBand1. Ну я думаю как оформить отчёт вы догадаетесь и без меня . Стоит отметить только ещё одну вещь. Если у вас не установлен принтер (ну нет принтера), то вам можно установить виртуальный принтер (печать в файл), иначе вы не сможете просматривать отчёты на своём компьютере. Для этого заходим в Панель управления->Принтеры и факсы, устанавливаем новый принтер. Выбираем локальный принтер, отменяя автоматическое определение, далее выбираем Использовать порт: File(печать в файл), далее выбираем любую марку принтера, ну а в остальном вы и без меня разберётесь. Нам осталось создать сводный отчёт (а то начальник обидится ). Для этого в Rave Reports заходим в меню File->New Report. В дереве справа появится созданный отчёт Report2. Добавляем Region, два бэнда и три датабэнда. На первом бэнде будет название отчёта, на втором – шапка для позиций заказа, датабэнды будут отображать данные, вот как всё это выглядит в дизайнере:
Теперь по порядку о настройках: 1. Band1 – BandStyle: Body Header(B), First(1) 2. DataBand1 – BandStyle: Group Header(G), First(1), New Page(P)
DataView: DataView5 3. DataBand2 – BandStyle: Detail(D), First(1), New Page(P) DataView: DataView4 ControllerBand: DataBand1 MasterDataView: DataView5 MasterKey: ID_KL DetailKey: ID_KL 4. Band2 - BandStyle: Body Header(B), First(1), New Page(P) ControllerBand: DataBand3 5. DataBand3 - BandStyle: Detail(D), First(1), New Page(P) DataView: DataView3 ControllerBand: DataBand2 MasterDataView: DataView4 MasterKey: ID_ZAK DetailKey: ID_ZAK Здесь я указал свойства отличные от свойств по-умолчанию, т.е. после добавления компонента надо установить эти свойства.А теперь вспоминаем добавленный RVTableConnection связанный с Tablе’ом Zakaz, получается данные у нас берутся из таблицы, а не запросом, ну конечно, а зачем нам нагромождать приложение лишними компонентами, если можно обойтись нашим Table’ом, ведь никаких ограничений на отбор данных в нём не стоит, и нас устроят те данные, которые в нём содержатся. С отчётом закончим, перейдём к программированию. Осталось только добавить следующий код на нажатие пункта меню Печать->Сводный отчёт: procedure TForm3.N6Click(Sender: TObject); begin Klient_svod.Close; Klient_svod.Open; Pos_zak_svod.Close; Pos_zak_svod.Open; RVProject1.Open; RVProject1.ExecuteReport('Report2'); RVProject1.Close; end;
Здесь я думаю всё понятно, принцип тот же самый как и при печати отчёта по заказу, отличие только в имени отчёта – Report2. Вид моего отчета ты можешь увидеть на рисунке ниже. На этом думаю можно закончить статью. Теперь ты можешь применять полученные знания на практике, возможно кто-то придумает более изящные методы программирования отчётов и поделится ими, буду только рад, ведь для этого и выкладываю эти статьи. В следующий раз покажу как использовать хранимые на сервере процедуры и функции в приложении.
by Ronin e-mail: master_t@inbox.ru
Работа с Oracle. Часть 4 Привет, это снова я. Вот собрался с силами и решил продолжить ваше знакомство с такой замечательной системой как Oracle. На этот раз я покажу как использовать хранимые на сервере функции. Вообще, функции, это довольно таки мощный инструмент. Их можно применять для выполнения всевозможных расчётов, привязать выполнение функции к событию какого-либо компонента, например кнопки. Думаю без использования таких объектов как функции, процедуры и т.д. сложно построить хоть сколько-нибудь серьёзную систему. Работать будем с уже разработанной в предыдущих статьях системой, так что прежде рекомендую прочитать. Итак, попробуем организовать формирование отчёта по состоянию заказа. В нём будет отображаться информация по товарам включённым в заказ, товарам уже отправленным и товарам оставшимся. Это необходимо для отслеживания выполнения заказа, в случае невозможности отправки заказа полностью. Прежде чем начинать действовать, необходимо составить план действий, так называемый проект, я бы даже сказал мини-проект. Итак, нам необходимо будет разработать возможность просмотра информации по выполнению (отгрузке) заказа. Это будет выглядеть следующим образом: пользователь встаёт на нужный заказ, нажимает печать отчёта "Выполнение заказа", в котором будет построчно выведена каждая позиция заказа с информацией о том сколько изделий заказано, сколько отправлено и сколько осталось на складе." Для реализации такой функции необходимо выполнить следующие скрипты (не забываем SQLPLUS): CREATE OR REPLACE function Kolvo (PID_STR in number) return integer is numrows integer; kolvo_otgr integer; BEGIN select count(*) into numrows from pos_nakl where pid_str=id_str; if numrows > 0 then select sum(kolvo) into kolvo_otgr from pos_nakl where pid_str=id_str; return (kolvo_otgr); elsif numrows = 0 then kolvo_otgr:=0; return (kolvo_otgr); end if; END Kolvo;
/ CREATE OR REPLACE FORCE VIEW SCOTT.ZAKAZ_SVOD (NOMER, KOLVO, DATA, NAIMEN, CHARACT, KLIENT, KOLVO_OTGR, ID_STR, KOLVO_OST) AS SELECT zakaz.nomer, pos_zakaza.kolvo, zakaz.data,
izdelie.naimen, izdelie.charact,klient.naimen as klient, kolvo(pos_zakaza.id_str) as kolvo_otgr, pos_zakaza.id_str, (pos_zakaza.kolvo-kolvo(pos_zakaza.id_str)) as kolvo_ost FROM zakaz, pos_zakaza, izdelie, klient WHERE
(zakaz.id_zak = pos_zakaza.id_zak) AND (izdelie.id_izd = pos_zakaza.id_izd) AND (zakaz.id_kl=klient.id_kl);
/
Теперь поподробнее о скриптах. В первом случае создаётся функция Kolvo которая получает в качестве входного параметра код строки заказа - PID_STR in number, здесь in означает что параметр входящий, number - тип параметра. return integer - показывает тип возвращаемого значения. Затем в переменную numrows отбирается количество строк (count), значения кода строки в которых соответсвуют значению параметра PID_STR, это делается для проверки наличия таких строк вообще, а затем выполняется проверка полученного значения переменной - если количество строк > 0 тогда выполняется подсчёт количества (sum(kolvo)) товаров в накладной, это число будет показывать отгруженные товары (kolvo_otgr). Если numrows меньше 0 - тогда kolvo_otgr присваивается 0. Таким образом, выполнением данной процедуры мы получаем информацию о количестве отгруженных товаров вы бранной позиции заказа. Далее мы создаём представление в котором отбираются информация по заказу, наименование клиента и строки позиций заказа, а также присутствует столбец kolvo_otgr который формируется посредством созданной нами процедуры Kolvo, и предназначен для отображения количества отгруженных изделий. Таким образом база подготовлена, приступаем к проектированию приложения. Добавляем компонент Query, не забываем давать осмысленные имена, у меня это Zakaz_svod, и добавляем компонент DataSource и связываем с нашим Query. Далее свойство DatabaseName у Query устанавливаем наш DataBase (у меня manuf), а в свойстве SQL у Query пишем следующее: Select * From ZAKAZ_SVOD Where NOMER=:nomer
Здесь мы отбираем все значения из представления ZAKAZ_SVOD в которых номер заказа совпадает со значением параметра nomer который мы будем устанавливать при печати отчёта. Заходим в свойство Params нашего Query, и в свойстве параметра nomer - DataType устанавливаем ftInteger. Далее как обычно заходим в редактор полей Query (двойной клик на компоненте), и добавляем все поля (add all fields). Теперь необходимо добавить компонент RvQueryConnection с закладки Rave и связать с нашим Query (свойство Query). Настройка компонентов выполнена, осталось связать печать отчёта с событием какого-либо компонента. Я решил это сделать через пункт меню Печать, добавив пункт "Выполнение заказа".
Далее на событие нажатия данного пункта меню прописываем следующий код: Zakaz_svod.ParamByName('nomer').Value:=ZakazNOMER.Value; Zakaz_svod.Open; RVProject1.Open; RVProject1.ExecuteReport('Report3'); RVProject1.Close; Zakaz_svod.Close;
Здесь мы задаём параметр для Query значением номера текущего заказа, и выполняем печать нашего будущего отчёта, я написал Report3, так как у меня он по счёту будет третий. Всё, проектирование приложения закончено, переходим к Rave Reports. Запускаем Rave Reports Designer, заходим в меню File->New report. Смотрим в дереве справа в ветке Report Library созданный отчёт, у меня получился Report3, соответственно и в приложении необходимо прописать имя этого отчёта, что я и сделал заранее. Ну а далее как обычно, добавляем Region с закладки Report, заходим в пункт меню File->New data object->Direct data view и выбираем наш RvQueryConnection, у меня получился RvQueryConnection5, здесь конечно тоже надо было давать RvQueryConnection осмысленное имя, тогда проще было бы выбирать из большого списка Connection'ов, но во всём виновата человеческая лень Затем последовательно добавляем два Band'а, один DataBand и один Band с закладки Report, вот что примерно должно получиться:
Затем рисуем вот такую ерунду:
Здесь поподробнее остановлюсь на свойствах компонентов (отличных от дефолтных, устанавливаемых по умолчанию): 1. Band2: BandStyle: GroupHeader, First, NewPage (поставить галки); ControllerBand: DataBand1; GroupDataView: DataView6 (связанный с RvQueryConnection'ом приложении); GroupKey: NOMER (группировка по номеру заказа); 2. DataBand1: BandStyle: Detail, First, NewPage; DataView: DataView6; 3. Band3: BandStyle: GroupFooter, First, NewPage; ControllerBand: DataBand1; GroupDataView: DataView6 (связанный с RvQueryConnection'ом приложении); GroupKey: NOMER (группировка по номеру заказа);
добавленым
в
добавленым
в
Остальные компоненты я думаю объяснять не надо, для надписей (шапка) используются компоненты Text с закладки Standart, для отображения полей с данными компоненты DataText с закладки Report, связанные с DataView6 и в свойстве DataField соответствующее поле. Единственно стоит только отметить компоненты отображающие итоги по количеству, они реализованы с помощью CalcText с закладки Report, у них установлены следующие свойства: 1. Суммарное кол-во в заказе: Controller: DataBand1; DataField: KOLVO; DataView: DataView6; Initializer: DataText6 (компонент в котором отображаются данные по количеству) 2. Суммарное кол-во отгруженное: Controller: DataBand1; DataField: KOLVO_OTGR; DataView: DataView6; Initializer: DataText7 отгруженному количеству)
(компонент
в
котором
отображаются
данные
по
3. Суммарное кол-во остаточное: Controller: DataBand1; DataField: KOLVO_OST; DataView: DataView6; Initializer: DataText8 (компонент в котором отображаются данные по оставшемуся количеству)
Вот вроде и всё, разработка закончена, при нажатии пункта меню Печать->Выполнение заказа видим вот такой отчёт:
При переходе на другой заказ будем видеть соответсвующие данные по заказу и товарам, если конечно сформированы предварительно накладные и указано количество отгружаемой продукции. Таким образом процедуры и функции позволяют реализовать сложные вычислительные механизмы не обременяя компьютер клиента, так как все расчёты производятся на сервере, в этом преимущество архитектуры клиент/сервер. Вот на сегодня и всё, увидимся вследующий раз, надеюсь
by Ronin e-mail: master_t@inbox.ru
Информационные технологии
Навесная защита vs Интегрированная Удаленное управление Ориентация на сервисы Миграция в открытый стандарт
Навесная защита vs Интегрированная Что лучше – интегрированная в железный или программный продукт безопасность или специализированная надстройка, которая закроет все возможные недочеты? Когда мне предложили проанализировать эту ситуацию, то я нашел в сети множество различных мнений, и многие из них заслуживают внимания, даже те, которые на наш взгляд являются ошибочными. Мы собрали различные мнения в одно целое и постарались выделить положительные и отрицательные стороны обоих методов защиты. Анализировать конкурирующие технологии всегда сложно, потому что, сколько людей, столько и мнений, но в любом анализе каждый из нас может найти что-то полезное. Если вы увидели, что какое-то мнение заведомо ошибочно, то сможете выбрать вариант лучше. Но все же, мнение большинства о чем-то говорит. Не могут же все ошибаться. Лично мое мнение – безопасность не зависит от того, какая используется защита. Это могут быть как навесные решения, так и встроенные и если о безопасности думают изначально и на всем жизненном цикле решения (планирование, разработка, внедрение, поддержка), то вне зависимости от вида, защита может обеспечить должный уровень безопасности. Тут еще необходимо добавить, что сама реализация должна быть выполнена на должном уровне, должно использоваться стойкое шифрование, и обеспечена корректная авторизация/аутентификация, при которой хакер не сможет скомпрометировать систему. Если систему разрабатывает не профессионал, то последнее условие может быть и не выполнено. Но если бы все было так просто, то мы не заводили бы этот разговор. Навесные и встроенные системы отличаются принципиально, поэтому давайте заглянем в корень и рассмотрим все преимущества и недостатки.
Установка Когда разрабатывался флагман современной сети - протокол TCP/IP, то разработчики явно не задумывались о том, что когда-нибудь появятся хакеры, а в сеть придет большой бизнес. Сеть создавалась больше для открытого общения, чем для коммерции или передачи секретных данных. Никто не задумывался о безопасности, поэтому TCP/IP лишен таких возможностей как шифрование, защиты от прослушивания, целостности трафика (защита от перехвата не является надежной). Открытость, это хорошо, но далеко не всегда и не везде. Ни одно предприятие не захочет, чтобы конфиденциальная информация была открыта конкурентам, ни один потребитель не захочет, чтобы его номер кредитной карты перехватил хакер. Получается, что требования безопасности необходимы не только поставщикам товаров или услуг, но и потребителям.
Навесной протокол В сети Интернет все данные передаются по протоколу TCP/IP. Протокол обладает множеством недостатков, вот только некоторые из них: • • • • •
нет шифрования; хакер может скомпрометировать систему; клиент и сервер не может гарантировать, что он общается именно с тем, за кого себя выдает оппонент; трафик может быть перехвачен; соединение может быть перехвачено.
Все эти недостатки очень серьезны, но почему же тогда этот протокол до сих пор используется? Ответ очень прост – сама сетевая модель была разработана гениально. Она состоит из семи уровней, а протокол TCP находиться ровно по середине, на транспортном уровне. Любое приложение, которому требуется работа с сетью, может использовать уже реализованные функции, а может на более высоких уровнях реализовать недостающие и необходимые возможности, как в домике из кубиков. Просто поверх TCP нужно поставить еще один кубик, который реализует необходимые возможности. Получается, что любой сетевой протокол, реализующий защиту, выполнен на основе TCP/IP, уже является навесным. Протокол является всего лишь транспортом и строительным кубиком. Да, хотелось бы, чтобы уже в нем были реализованы какие-то возможности, но «хотелось» не всегда совпадает с действительностью.
Программа без навеса Вы наверно не раз слышали, что для того, чтобы программа работала безопасно, нужно изначально думать именно об этом и стремиться к безопасности. Если программа изначально написана без заботы о защите пользователей, то сделать что-то будет намного сложнее. Когда средства защиты уже реализованы в программе, то мы получаем следующие преимущества: 1. Можно надеяться (а чаще всего данный пункт становиться фактом), что установка пройдет гладко и без проблем. Не нужно настраивать отдельное приложение, которое будет обеспечивать безопасность (например, шифрование). Установка и настройка упрощается, и очень часто это является серьезным плюсом, особенно в больших компаниях с сотнями компьютеров. Когда у администратора в подчинении большое количество хостов, то один из первичных факторов является быстрота и удобство установки и конфигурирования. 2. Меньше вероятность встретить конфликты, между различными модулями. Это основные преимущества. Надежность решения в преимущество или недостаток внести мы не можем, потому что тут все зависит от конкретной реализации. Исходя из практики, можно выделить следующие недостатки: 1. Как показывает жизнь, далеко не все программисты являются специалистами в области безопасности и это нормально. Знать все нереально, а если кто-то будет знать все, то жить будет скучно. Получается, что если компания разрабатывает сетевую программу и пытается реализовать встроенную возможность шифрования, то не имея соответствующих специалистов, может получиться далеко не защищенный продукт. 2. Не редко, теряется гибкость, если система реализована под определенное оборудование или протокол. Гибкость теряется и в методах защиты, например, в поддерживаемых алгоритмах шифрования. Ведь если компания не специализируется на безопасности, то она не может предусмотреть всего. 3. Очень часто, для встроенной защиты используется сторонний пакет. Если у вас нет возможности обновлять этот пакет, то могут возникнуть проблемы. Например, вы купили программу XXX. Она использует для шифрования трафика OpenSSL. Если в функциях этого пакета найдена ошибка и разработчики выложили исправление, то вы должны иметь возможность обновить необходимые библиотеки, без ожидания заплаток от разработчика программы XXX. Ведь если разработчик окажется не расторопным, то ваша система будет находиться под угрозой.
Под навесом
Навесная защита позволяет защитить даже то, что изначально не было безопасным. Яркими примерами являются VPN и туннели с шифрованием трафика. На мой взгляд, это решение лучше, но это лично мое мнение. Каждый должен сделать свой выбор. Сначала рассмотрим преимущества навесной защиты: 1. Чаще всего защита разрабатывается специалистами в этой области. Если же автором программного комплекса является доморощенный программист, решивший потренировать мозги, то при наличии плохой реализации такой продукт не получит достаточного распространения. Выбирая проверенные зарекомендовавшие себя решения, у вас больше шансов получить качественную защиту. 2. Распространенность системы позволяет гарантировать, что систему протестирует множество хакеров, и если ошибки найдут, то их обязательно исправят. Если разработчик солидный, то ошибки исправят оперативно. 3. Можно защитить даже то, что изначально не было защищено. Например, всеми известный протокол Telnet. Передаваемые по нему данные абсолютно не защищены и любой специалист скажет вам, что этот протокол использовать нельзя. Но если telnet трафик аккуратно завернуть в stunnel, то хакеры будут нервно курить в сторонке. Еще один пример – протокол FTP, с помощью которого мы передаем файлы. Он изначально не защищал свои каналы и передаваемые данные, но обернув трафик шифруемым туннелем, мы получаем sftp и понимаем, что жизнь прекрасно. Серьезных недостатков такой защиты выявить сложно, иначе она не получила распространения и навесные защиты уже давно умерли, но это не значит, что минусов нет вообще. Они есть, их не может не быть. Основной минус – это распространенность. Этот же пунктик был среди положительных сторон, так как же он попал в недостатки? Популярность всегда имеет две стороны медали и обратная заключается в том, что если кто-то найдет ошибку, то пострадают все пользователи, использующие данный продукт. Этот недостаток легко решается тем, что нужно регулярно обновлять системы безопасности. Нет ничего идеального. На своем сайте www.flenov.com я регулярно выкладываю свежие уязвимости и знаменитая Cosco, фигурирует в нем как минимум раз в неделю, хотя эта фирма специализируется на безопасности и там работают много талантливых и умных программистов. Второй минус – необходимость устанавливать отдельный продукт и конфигурировать его. Допустим, что вы хотите спрятать telnet трафик. Для этого нужно: 1. Установить программу, которая будет организовывать защищенный канал с сервером, и сконфигурировать ее на прослушивание определенного локального порта и перенаправление зашифрованного трафика на сервер; 2. Нужно закрыть сетевым экраном локальный порт тунеля, чтобы к нему не могли подключаться извне. Только локальный пользователь может его использовать для подключения к серверу. При большом количестве компьютеров в сети, не каждый администратор решиться делать эти настройки на всех компьютерах. Можно создать какой-то сценарий или программу, которая будет автоматизировать процесс установки, но это лишние затраты. С другой стороны, эти затраты себя окупают. Один раз настроил и спи спокойно.
Смесь Несколько раз я встречал, что трафик приложения, которое имеет хорошие встроенные механизмы защиты (например, шифрование) дополнительно защищался навесной защитой.
Получается, двойное шифрование. На первый взгляд, это избыточно, но давайте посмотрим на это с обеих сторон медалей. Если в механизмах защиты программы будет найдена ошибка, то хакер не сможет воспользоваться этим, потому что весь трафик шифруется еще одним алгоритмом. Если же ошибка найдена в навесной защите, то хакер сможет расшифровать первый слой, а второй останется недоступным. Вероятность того, что ошибка будет найдена в обоих алгоритмах, на мой взгляд, ничтожна мала. То есть двойная защита позволяет снизить риск потери данных! С другой стороны, накладные расходы перед передачей данных и после их приема значительно возрастают. Если оба алгоритма защиты тратят одно и то же время и одинаковое количество ресурсов, то нагрузка и задержка увеличиваются в два раза. А оно нам надо? Защиты много не бывает, и мы думаем, что любые накладные расходы не сравнимы с потерей данных. Лучше потерять в производительности, чем лишиться конфиденциальной информации. Я не специалист в шифровании, но год назад на форуме http://www.windowsecurity.com/ был спор – действительно ли двойное шифрование дает преимущество? Мнения были разные, и один из оппонентов утверждал, что если иметь какой-то слепок, то можно расшифровать данные одним проходом. Не нужно будет расшифровывать данные по отдельности. Я не уверен, что такое возможно.
RSA и VPN
Разработчику Не каждому дано написать хорошую защиту, поэтому, если вы являетесь разработчиком, то мой вам совет – без достаточного опыта и знаний, даже не пытайтесь что-то создавать в этой области. Воспользуйтесь уже готовыми решениями. Есть мнение, что самостоятельно написанная защита лучше, потому что в ней хакеру будет сложнее разобраться. Это заблуждение. Да, не так много людей, которые способны находить ошибки, большинство пользуются плодами других исследователей безопасности. Но если опытный хакер займется вашей системой, то все может закончиться плачевно.
Не стоит изобретать велосипед. Воспользуйтесь уже готовыми и проверенными решениями. Это будет проще в реализации и надежнее в эксплуатации. Немаловажным фактором является скорость разработки решения. Если вы воспользуетесь уже готовым, то меньше времени понадобиться на разработку. А если еще вспомнить, о необходимости лицензировать разрабатываемые системы безопасности, то приходим к выводу, что лучше не связываться с самостоятельной разработкой.
Администратору Если вы выбираете готовое решение для своей сети, то обязательно проверьте, как построена защита. Если она встроенная, то нужно выяснить, какие алгоритмы шифрования, авторизации и аутентификации поддерживаются. Ну и самое главное - какие пакеты используются. Далеко не всегда встроенная защита написана самостоятельно. Как мы уже говорили, программа может использовать чужие библиотеки. Если эти библиотеки используются без модификации, то вы сможете их обновлять независимо от разработчика программы. Но если в библиотеку внесены очень важные изменения, то ваше обновление может привести к краху. Я вообще не являюсь сторонником того, чтобы кто-то со стороны вносил изменения в стандартные библиотеки, потому что сами изменения могут привести к лишним ошибкам из-за того, что разработчик лучше знает, что и для чего он делал в библиотеке.
Клиент Открытые данные Программа шифрования Зашифрованные данные Интернет Зашифрованные данные Дешефрование Открытые данные Сервер Работа туннеля
VPN и Windows
by Фленов Михаил aka Horrific E-mail: info@vr-online.ru
Удаленное управление Я сменил всего три места работы, но везде администраторы для выполнения каких-либо действий на удаленной машине используют RAdmin или DameWare. Это действительно мощные программы, которые позволяют организовать удаленный контроль машиной, но они нужны далеко не всегда. Очень часто можно обойтись средствами Windows и серьезно сэкономить трафик. Сегодня я покажу тебе, что и как можно делать с удаленным компьютером средствами окон.
Права доступа Прежде чем начать рассматривать удаленный контроль, необходимо определиться с правами доступа. Если у тебя сеть построена на основе контроллера домена Windows NT/2000/2003, то по умолчанию, администратор домена имеет права локального администратора на всех компьютерах сети. Хочешь убедиться? Если у тебя есть доменная сеть, то запусти на своем компьютере оснастку Управление компьютером (Computer Management). Это можно сделать из "Панель управления" "Администрирование" или щелкнув правой кнопкой по "Мой компьютер" и выбрав меню "Управление" (Manage). Здесь в дереве объектов слева выбери раздел "Управление компьютером/Служебные программы/Система/Локальные пользователи и группы/Группы" (Computer management/System tools/Local Users and Groups/Groups). Справа должен появиться список всех групп. Щелкни дважды по группе Администраторы (Administrators) и здесь в списке ты увидишь помимо своей учетной записи (если ты конечно локальный админ) еще и администраторов домена.
Просмотр групп пользователей через оснастку "Управление компьютером"
Чем грозят права локального бога администраторам домена? Они имеют полный контроль над твоей машиной (дальше мы увидим как). Если ты не хочешь, чтобы без твоего ведома у тебя на машине кто-то ковырялся, срочно удали администраторов домена из группы локальных богов. Если ты сам бог своей сети, то должен контролировать, чтобы пользователи не выкинули тебя из локальных администраторов на своих компьютерах.
Если доменной сети нет, то для удаленного управления необходимо знать пароль администратора компьютера, которым ты хочешь управлять. Теперь, чтобы коннект прошел удачно, установи себе этот же пароль, иначе могут быть проблемы с соединением. Внимание! У тебя должен быть Windows из серии сервера или Professional. В Windows XP Home Edition работа в домене заблокирована. Я слышал, что умельцы вроде бы вводили Windows HE в домен, но сам не пробовал, поэтому подтвердить эту информацию не могу.
Я сам себе бог, а админы домена мне не указ
Итак, чтобы можно было удаленно управлять чужой тачкой, у тебя должно быть одной из двух: 1. Ты должен быть администратором домена и при этом, на удаленной машине тебя не выкинули из локальных богов; 2. Ты знаешь пароль админа жертвы и установил себе такой же. Если хотя бы одно из этих условий выполнено, удаленный контроль будет возможен.
Реестр Одна из частых задач, с которой приходиться сталкиваться администратору – это правка реестра и управление правами доступа к нему. Чтобы подправить реестр абсолютно ненужно подключаться к удаленной машине. Достаточно запустить regedit на своем компьютере и выбрать меню "Подключить сетевой реестр" (Connect Network Registry) из меню Файл (File). Перед тобой появиться окно, в котором можно выбрать компьютер, реестр которого ты хочешь подключить. Введи имя компьютера в большое окно ввода и нажми ОК. Если у тебя есть нужные права и имя введено правильно, то в окне regedit появиться еще одна корневая ветка, в которой будет реестр удаленной тачки. Теперь, управляем удаленным реестром так же, как и своим собственным. Не знаю, почему многие запускают для правки реестра RAdmin, когда проблема решается намного проще и с большой экономией трафика.
Подключение к удаленному реестру
Полный контроль Для управления собственным компьютером мы используем оснастку Управление компьютером (Computer Management). Но почему-то не многие знают, а если знают, то не используют эту оснастку для управления удаленным компьютером. Здесь также можно подключиться к машине пользователя и управлять им, как своим собственным. Выполняем следующие действия: 1. Запусти оснастку Управление компьютером; 2. Выбери в дереве объектов первый пункт - Управление компьютером (Локальный) 3. Выбери меню "Действия – Подключение к удаленному компьютеру" (Action – Connect to another computer). Если второе действие не выполнить, то меню, описываемое в третьем действии не будет доступно!
Подключение к удаленному компьютеру
Появиться окно подключения к компьютеру. Здесь два переключателя – локальный компьютер и удаленный. Выбери второй вариант, и введи имя компьютера. Если у тебя достаточно прав, то подключение пройдет удачно.
Просмотр событий Что мы можем теперь делать? Да все то же самое, что и с локальным компьютером. Допустим, что тебе звонит блондинка.... Стоп, не будем переходить на личности, ведь далеко не все блондинки такие же, как в анекдотах. У меня жена тоже блондинка... Стоп, тут я уж точно промолчу, дабы не зарабатывать себе приключения на мой розовый зад. Короче, тебе звонит пользователь (пол и цвет волос не уточняем), который не дружит с английским и сообщает, что Windows или другая программа проматерилась на английском. Попытки пользователя прочитать сообщения не приводят ни к чему хорошему, потому что понять ламерский английский можно только после пятой бутылки пива. Ну да ладно, подключаемся с помощью оснастки "Управление компьютером" и смотрим системные сообщения в ветке "Служебные программы/Просмотр" событий (System tools/Event Viewer). Здесь есть три подраздела:
Просмотр системных сообщений Windows
1. Приложения (Application) – здесь различные приложения оставляют свои сообщения об ошибках и различные предупреждения; 2. Безопасность (Security) – здесь система оставляет свои сообщения, касающиеся безопасности – смена паролей, блокировки и т.д. Если пользователь не может войти в свой компьютер, то подключись и посмотри сообщение в журнале безопасности. Возможно, сообщения помогут тебе быстро решить проблему, а заодно, сэкономить тонну трафика; 3. Система (System) – здесь система оставляет свои сообщения. По моей статистики сообщения в основном помещаются сюда на этапе загрузки ОС, но могут попадать и во время работы. В Windows 2003 может быть больше разделов. Например, если у тебя установлена репликация, DNS и активная директория, то появятся соответственно разделы File Replication Service, DNS Server и Directory Service.
Управление шарами Для удаленного управления шарами нам снова понадобиться оснастка "Управление компьютером". Раскрой ветку "Служебные программы/Общие папки" (System tools/Shared Folders). Здесь находиться три папочки: 1. Общие ресурсы (Shares) – открытые ресурсы (папки или диски). Чтобы закрыть какой-то из ресурсов, который пользователь открыл по своей оплошности, щелкни по нему правой кнопкой мыши и выбери в появившемся меню Stop Sharing. Если необходимо открыть какой-то ресурс для пользователей, снова щелкаем правой кнопкой и выбираем пункт меню New Share. При этом в списке шар не должно быть ничего выделенного. Только не забудь, что ты подключен к другому компьютеру, и необходимо указывать корректный путь именно для этого компьютера, а не для твоего. 2. Сеансы (Session) – здесь можно промониторить, кто сейчас подключен к данному компьютеру и сколько ресурсов открыл. 3. Открытые файлы (Open files) – здесь нам покажут, какие именно файлы или папки открыты и каким пользователем.
Открытые ресурсы
Управление шарами удобно не только для контроля открытых ресурсов в твоей локальной сети, но и для просмотра того, кто и что открывает на твоем компьютере. Ты хоть иногда следишь за открытыми шарами? А зря. У меня на работе админ такой же растяпа. Мне как программеру необходимы права бога в домене, чтобы я мог управлять пользователями напрямую, а у нашего админа администраторы домена не отключены из локальных богов. Поэтому, я иногда прикалываюсь. Конечно, чужой диск я не просматриваю, потому что не имею привычки ковыряться на чужом диске, но поле деятельности для шуток достаточно большое.
Сникерсни Когда мне говорят, что сервер тормозит, я не спешу подключаться к нему удаленно через RAdmin, ведь это все равно даст плохой результат с точки зрения диагностики. Программа RAdmin не волшебник и не может сидеть в системе, не поедая ресурсов, особенно сетевых, поэтому реальную производительность за минусом расходов процессора на обслуживание
RAdmin рассчитать сложно. Из-за такого удаленного подключения лишняя нагрузка ложиться и на сетевые драйверы, а ведь нужно еще запустить какое-то средство диагностики. А не лучше ли запустить утилиту диагностики у себя на компьютере и подключиться к удаленной машине? Конечно же лучше и это возможно сделать средствами наших любимых/не любимых (ненужное зачеркнуть) окошек. Заходим в Панель управления, затем Администрирование и запускаем оснастку Производительность. В дереве слева выбираем пункт Системный монитор и наслаждаемся графиками производительности. По умолчанию нам будут показывать состояние трех параметров – память (обмен страниц в секунду), диск (длина очереди диска) и загруженность процессора. Все очень наглядно, потому что каждый параметр рисуется линией своего цвета.
Мониторить производительность можно и удаленно
Черт побьери. Это же параметры моего компьютера, а нам нужно промониторить сервер по имени MainServer. Не проблема. Шашки на голо и нажимаем кнопку Ctrl+I. Перед тобой откроется окно добавления счетчика. Обрати внимание, что вверху есть переключатель – использовать локальные счетчики и выбрать счетчики с компьютера. Если выбрать второй вариант, то можно будет ввести имя компьютера, параметры которого нас интересуют. После этого нужно определиться с параметром, который мы хотим проконтролировать. В выпадающем списке выбираем объект, и чуть ниже уточняем, какой именно параметр ты хочешь проконтролировать. Если какой-то параметр не понятен, не стесняйся нажать кнопку "Объяснение" и воспользоваться подсказкой. Продвинутые админы тоже иногда должны читать помощь и пользоваться подсказкой, тут ничего зазорного нет. Если сильно стесняешься, прикрой монитор рукой или поверни так, чтобы никто не видел. Когда определишься и выберешь, что нужно, нажимай кнопку "Добавить".
Оснастка Производительность предоставляет графически практически любой параметр
Исходя из личных наблюдений, ни разу не видел, чтобы кто-то использовал эту оснастку даже для локального мониторинга, не говоря уже об удаленной машине. Большинство админов предпочитают подойти к серверу или подключиться через RAdmin и нажать заветные три буквы, т.е. три клавши Ctrl+Alt+Del и наблюдать за производительностью здесь. Не понимаю, почему так? Да, три клавиши нажать легче, но там информации очень мало, чтобы сделать хоть какие-то нормальные умозаключения о реальной производительности. А если учесть, сколько калорий уходит на то, чтобы физически подойти к серверу для нажатия клавиш, то понимаешь, почему админы худые при том, что они питаются гамбургерами. Оснастка "Производительность" (Perfomance) намного информативнее, удобнее и намного лучше показывает данные при удаленном мониторинге.
Служу советскому союзу Иногда приходят жалобы, что накрылась какая-то служба или она вообще не была установлена в автостарт, а тут вдруг понадобилась. Чтобы исправить положение и сделать это эффективно, нужно подключиться к удаленному диспетчеру служб. И самое интересное, что оснастки Windows умеют это делать. Во первых, службами можно управлять через Управление компьютером. Эту оснастку мы уже рассматривали и там есть раздел "Службы и приложения" – "Службы".
Подключение к удаленной машине в оснастке Сервисы
А можно использовать и более привычную оснастку Службы, которая находиться в "Панели управления" – "Администрирование". Запусти эту оснастку и выбери меню "Действие""Подключение к удаленному компьютеру". Перед тобой должно открыться окно для выбора компьютера. Где-то мы это окошко уже видели. Я думаю, дальнейшие комментарии по управлению службами уже излишни.
Движение далее Как видишь, очень многое можно сделать без загрузки прожорливых в отношении трафика утилит RAdmin или DameWare. Пользуйся оснастками Windows, ведь они достаточно удобный и эффективны не только в локальной настройке, но и удаленной. А самое главное, встроенные утилиты уже установлены и ничего не будут тебе стоить, т.е. абсолютная халява. Ну разве это не счастье! Я рассказал тебе только про основные оснастки, которые использую сам для удаленного управления и мониторинга в своей сети/домене. Но это не предел. Большинство оснасток, которые ты можешь увидеть в "Панель управления"/"Администрирование" умеют удаленно работать с другими компьютерами. Рассматривать их все не имеет смысла, потому что принцип работы почти везде одинаковый – выбрать меню "Действие"-"Подключение у удаленному компьютеру". В этом отношении сильнее всех отличается только оснастка контроля производительности. А если попытаться описать все, то это отняло бы очень много времени, ведь в Windows 2003 при установленной активной директории и всеми установленными сервисами, панель администрирования просто переполнена. Именно поэтому, я ограничился основными параметрами системы, которые мы используем чаще всего и которые могут пригодиться тебе.
В Windows 2003 оснасток еще больше. Их количество зависит от установленных сервисов, а у меня еще не установлена AD
В Windows 2003 оснасток еще больше и для удаленного управления ими на сервере со своего компа тебе придется тоже ставить Windows 2003, чтобы такие же оснастки были и в твоей тачке. Если не хочешь держать такого монстра у себя, то оснастки можно перенести и на Windows Professional, а можно воспользоваться сторонними утилитами, предоставляющими удаленное управление.
Итог Напоследок хочу рассказать тебе про одну поучительную программулинку. Недавно видел программку Российского производства, которая умеет сканировать сеть на наличие компьютеров, найденные компьютеры расставлять на форме, сканировать порты, пинговать и управлять удаленным компьютером. Удаленное управление включает в себя – работу с реестром, просмотр шар сервисов и пользователей ну и еще пару параметров, точно не помню.
Короче, возможности удаленного управления примитивны, программа ужасна, а сканеры сети, портов и пингер можно найти в инете и на халяву. А знаешь, сколько стоит эта программа? Ты не поверишь – более $100. Точную сумму не буду называть, чтобы ты не упал в шок, потому что она больше, чем стоит Windows Home Edition! Нет, я не ругаю разработчика за наглость, я восхищаюсь. Если программа реально продается и приносит прибыль, то разработчик – молодец, а админы, которые платят за нее деньги – лохами были, такими и останутся. Изучай возможности Windows и ты сэкономишь себе уйму денег и времени и тебя не разведут, как ламера за примитивную и не нужную программу на сумму, равноценную целой операционной системе. Удачи, и до новых встреч.
By Фленов Михаил aka Horrific E-mail: info@vr-online.ru
Ориентация на сервисы Некоторые считают, что Россия в области ИТ движется очень быстро, и мы скоро всех догоним и перегоним. Так ли это? Я думаю, что нет. Например, в корпоративных приложениях мы застряли в архитектуре клиент-сервер. Лично я очень мало видел многоуровневых решений российской разработки, а сервис ориентированная архитектура вообще диковина. Многие просто до конца не понимают, что это такое, где использовать, и какие мы получаем преимущества. Некоторые считают, что сервисы используются только в WEB приложениях и только на Java или .NET, а в других приложениях абсолютно не нужны. Это серьезное заблуждение. Да, в языке программирования Java уже есть множество классов, которые упрощают разработку, но это не значит, что эта технология не может быть написана на другом языке. Подойдет абсолютно любой язык программирования, умеющий работать с TCP/IP протоколом. Да, протокол общения с сервисом использует в качестве базы HTTP запросы, но это не значит, что использование сервисов ограничено только WEB браузером. В браузере уже реализованы все необходимые функции для работы с HTTP и XML, но кто мешает реализовать то же самое в вашем корпоративном приложении и получить преимущества SOA? Хотя, последние тенденции показывают, что ИТ сдвигается в сторону WEB, а тут преимущества SOA проявляются в полной степени.
Что это такое? Что такое архитектура SOA (service oriented architecture, сервис ориентированная архитектура)? Уже из названия понятно, что основа – это сервисы. Сервис можно воспринимать как программу, которая умеет выполнять какое-то действие по внешнему запросу и при необходимости может возвращать результат. В некоторых источниках можно встретить, что сервис – это что-то более крупное, чем CORBA, а в других говорят, что сервис маленький, но их множество может объединяться в стек. Из-за многообразий формулировок и начинается путаница и появляется неопределенность. Я придерживаюсь мнения, что сервис может быть любого размера и не имеет значения - больше он или меньше CORBA объекта. Главное, чтобы это был законченный объект, который будет выполнять необходимые действия и прятать от потребителя услуг внутреннюю работу. Я не даром употребил слово «объект», потому что аналогия с этой технологией действительно прослеживается. Сервис можно воспринимать как функцию, которая может находиться удаленном компьютере (а может и локально), и при этом выполняет какие-то действия, а входные параметры и результат передается по сети. Внешнее приложение (корпоративная программа, WEB браузер или даже небольшая программа на карманном компьютере) используют этот сервис для получения или управления данными. Чтобы внешние программы могли взаимодействовать с сервисом, существует стандартный протокол SOAP (Simple Object Access Protocol, простой протокол доступа к объектам), который основан на HTTP запросах. В основе протокол отправляет серверу запросы (например, POST) по HTTP, внутри которых находиться SOAP запрос в виде XML схемы. Результат работы сервис возвращает также по HTTP протоколу, в который завернут SOAP ответ в виде XML схемы.
Для доступа к SOA можно использовать не только SOAP, но и уже упомянутую CORBA или собственную разработку. Идеология от этого не измениться. Но на наш взгляд, SOAP является лучшим решением, поэтому в данной статье будем рассматривать SOA и SOAP в связке.
Яркий пример Чтобы увидеть всю мощь рассматриваемой архитектуры, давайте сразу рассмотрим небольшой пример. Наибольшую эффективность и наглядность можно обеспечить именно в WEB, наверно поэтому здесь сервисы получили наибольшее распространение и почти везде выражения SOA и WEB сервисы объединены в одно целое. Допустим, что вы разрабатываете WEB магазин продажи книг. Можно просто составить каталог книг и никак не отслеживать наличие товара на складах и возможность поставок, но такое положение дел не устроит посетителей вашего магазина. Будет очень некрасиво, если посетитель закажет и оплатит книгу, которая не издавалась уже 5 лет. Вы попадете в нехорошее положение из-за того, что не сможете выполнить заказ, а посетитель уйдет в следующий раз в другой интернет-магазин.
Выделенная книга уже больше года отсутствует на складе издательства и доп. тиражей нет, а посетитель магазина этого не знает и может ждать своего заказа вечно
Чтобы отслеживать возможность поставки товара, вы можете сделать запрос к WEB-сервису оптовой компании, где закупаются книги. Он может вернуть вам количество книг на оптовом складе, дату ближайшей поставки и срок поставки, если книги нет на складе. Используя эту информацию, вы можете сообщить посетителю более-менее реальные данные, когда он сможет получить свою книгу, если ее нет в магазине.
С другой стороны, WEB сервис оптового магазина, для обработки запроса клиента проверяет остатки собственной базы данных товара и запрашивает WEB сервис издателя книги, чтобы тот сообщил: • • •
а есть ли книга у издательства; если нет, когда будет переиздание; когда издательство может осуществить поставку оптовику, и с какого склада (чаще всего не столичные издательства имеют локальный склад плюс по одному в Москве и в СанктПетербурге);
Обращение к службам
Обращение интернет магазина к сервису оптовой компании и далее к сервису издательства, называется b2b (business to business). Такое общение, позволяет магазину предоставлять посетителю максимально полную и приближенную к действительности информацию, а магазину и оптовой компании оптимизировать хранение товара на складе. Например, если WEB-сервис издательства сообщает, что какая-то книга может быть поставлена в течение 10 дней, а по статистическим данным оптовая компания видит, что на складе товара осталось максимум на 9 дней, то отделу снабжение может быть предложено сформировать заявку на допоставку товара. Это избавит вас от перебоя в поставках при минимальных затратах на хранение. А если сервисы будут отображать не только состояние склада, но и изменения цены? Ведь цена книг может меняться (инфляцию никто еще не отменял) и если магазин не отреагирует, то может начать торговать в убыток. Если цена будет контролироваться через WEB сервисы, при повышении цены издательства или стоимости поставки, интернет магазин благодаря WEB сервисам может мгновенно отреагировать. Можно пойти дальше – магазин может автоматически устанавливать свою розничную цену как:
цена оптовой компании + цена поставки + N% прибыли
и в этом случае магазин никогда не будет торговать в убыток.
Конкурентные преимущества На данный момент для организаций WEB – лучший способ предоставить своим клиентам подобные рассмотренному выше сервисы в реальном времени. Рассылка дисков почтой и баз данных по E-mail устарела, а программная обработка содержимого WEB страниц, где компании показывают состояние своих товаров - возможна, но очень сложная в реализации и чувствительна к любым изменениям в структуре HTML документов. Как много в России компаний предоставляет своим клиентам что-то подобное? Оставим вопрос открытым. Большинство интернет магазинов отображают возможные сроки поставки, добавляя к текущей дате заранее определенное число. Чтобы убедиться в этом, достаточно сравнить срок поставки на несколько отсутствующих товаров и 90% случаев, они будут одинаковы. В связи с этим, появление у какой-либо компании полноценных сервисов, используемых не только внутри компании, но и предоставляемых для нужд клиентов и партнеров, будет является серьезным конкурентным преимуществом, позволяющим оптимизировать состояние складов и затрат на хранение товара.
Независимость от языка Технология SOA предоставляет нам великолепную (возможно даже лучшую) независимость от всего, а самое главное - от языка программирования и от ОС. Языки программирования развиваются очень динамично. Еще десять лет назад балом правил С++ и его позиции казались непоколебимы, но два года назад пальму первенства отобрал Java. Да, в нашей стране это не так заметно, но я всегда говорю – посмотрите предложение о работе в США и Канаде и вы увидите, что мы серьезно отстали. Наибольший спрос на Java и SOA. Еще пару лет назад всем казалось, что Java отобрал пальму первенства всерьез и надолго, но новинка от MS в виде технологии .NET пусть и медленно, но набирает обороты и каждый год откусывает небольшой кусок пирога от J2EE. В этот момент программисты начинают задумываться – что победит, и какой язык использовать? Все мы можем только догадываться, и кто-то может угадать, но сказать точно мы не беремся. Используя сервисы, вам абсолютно все равно, какой язык победит. Один сервис может быть написан на Java, другой на C#, а третий на С++ и все они будут прекрасно дружить и совместно работать на благо компании. Мне уже несколько раз приходилось участвовать в авантюрах, когда на предприятии приходиться переписывать тонну кода только из-за того, что старая программа написана на языке, который больше не развивается и не может обеспечить потребности компании. Например, сейчас я занимаюсь переписыванием кода с Power Builder на Delphi. Это грозит кардинальными изменениями, потому что переписывать приходиться сразу все. Если бы корпоративная программа использовала бы SOA архитектуру, то переход можно было бы делать постепенно. А можно поступить еще лучше – перенести на другой язык только те сервисы, которые действительно нуждаются в этом и где старый язык не может реализовать необходимые потребности. Те сервисы, которые и так работают хорошо, можно оставить без изменений. Главное – отказаться от монолитных решений, которые неудобны и неповоротливы.
Независимость от платформы Протокол SOAP, который используется для обмена информацией, базируется на двух открытых стандартах XML и HTTP. HTTP и XML независимы от платформы, а значит сервисы могут работать на любых платформах, лишь бы там была поддержка TCP/IP. А так как этот протокол реализован практически во всех современных устройствах и ОС, то границ для рассматриваемой нами архитектуры практически нет. Ваше Windows приложение может без проблем обращаться к сервису, работающему на Linux и наоборот, а с помощью браузера к сервису можно обратиться даже с мобильного телефона.
Многоразовое использование Большинство новых технологий обязательно старается учитывать то, что код должен использоваться максимально эффективно. Если возникает необходимость в новом месте решить уже реализованную ранее задачу, то код не должен переписываться заново. Сервисы решают эту проблему великолепно, и даже там, где программы реализованы различными производителями.
Совместное использование сервисов
Архитектура SOA позволяет вам создать один сервис, который будет являться поставщиком данных не только для WEB приложения, но и для различных модулей корпоративного программного обеспечения. Очень часто, различные модули должны работать с одними и теми же данными, просто отображать могут их по-разному. Например, остатки по складу могут быть нужны отделу снабжения, кладовщику, аналитику, маркетологу и т.д. Реализовывать в каждом из модулей функции отображения нужных данных слишком невыгодно и расточительно. Достаточно написать один сервис, который будет возвращать XML схему с остатками запрошенного товара, а клиентской программе остается только отобразить содержимое схемы в удобной пользователю форме. Благо XML с его расширениями XSL, DTD предоставляет широкие возможности по форматированию.
Связь приложений Допустим, что вы стремитесь идти в ногу со временем и используете все современные программные пакеты для управления затратами, клиентами поставщиками и т.д. На рынке сейчас можно увидеть множество различных систем ERP, CRM и др. продуктов от разных производителей. Но как их заставить работать вместе? Необходим какой-то механизм, который позволит модулям и программным пакетам обмениваться информацией, чтобы не приходилось информацию об одном и том же поставщике вводить в две разные базы данных. В качестве стандарта при обмене информацией становиться XML, потому что он простой, удобный, мощный и независим от платформы. А так как SOA возвращает данные в виде XML, то вполне логично было бы сделать так, чтобы различные модули и программы могли сами запрашивать нужную информацию у сервисов.
Догоним и перегоним Возможно, что в нашей стране предприятия не используют сервисы только из-за специфики бизнеса "по-русски", а может просто потому, что руководству никто не показал преимущества, которые предоставляет SOA. Если вы до сих пор не увидели все достоинства этой архитектуры, тогда мы идем к вам. За дополнительной информацией я бы рекомендовал обратиться к сайту www.ibm.ru, где собрано множество статей по рассмотренной архитектуре. Особенно, стоит обратить внимание на следующие ссылки: http://www.ibm.com/developerworks/ru/webservices/ http://www.ibm.com/developerworks/webservices/newto/websvc.html http://www.w3.org/TR/2000/NOTE-SOAP-20000508/ http://www.ibm.com/developerworks/ru/library/ws-whyesb/
by Фленов Михаил aka Horrific E-mail: info@vr-online.ru
Миграция в открытый стандарт В последнее время в нашей стране наметилась положительная тенденция в сторону использования лицензионных программ. Большое количество судебных процессов против нарушителей лицензий и изменения нашего сознания от воровства в сторону легальной жизни не может не радовать. Но для любой компании использование лицензионного грозит большими расходами. Посчитайте сейчас, сколько денег нужно, чтобы установить на каждый компьютер легальную копию MS Windows, MS Office и антивирус в коробочном варианте. Расходы будут соизмеримы со стоимостью неплохого офисного компьютера! Нужно как-то экономить. Маленькие компании имеют слишком маленькую прибыль, чтобы тратить на ИТ и на программное обеспечение большие деньги, а в больших компаниях слишком много компьютеров, и сумма расходом может быть равной бюджету Африканской страны. Сколько денег ваша компания тратит на программное обеспечение? Вы считаете, что эти расходы оправданы? Если нет, то не пора ли перейти на открытую платформу. Это позволит вам не заботиться о лицензиях, использовать программы без зазрения совести, что они пиратские и может быть даже лучше решать поставленные задачи.
Переход на лицензию В одной из компаний, где я работал два года назад, было не более ста компьютеров. Когда директор узнал о возможных проблемах из-за отсутствия лицензии, то он решил купить все легально, чтобы не испытывать судьбу. Мы стали достаточно экономно считать, сколько денег нужно на выход из тени, и получилось, что нужны следующие продукты: 1. MS Windows на все компьютеры; 2. Антивирус Dr.Web на все компьютеры; 3. MS Office на 20 компьютеров, где он действительно нужен и будет использоваться; 4. Три Windows 2000 Server для трех офисов; 5. Три MS SQL Server для трех офисов; 6. Среда разработки Borland Delphi 7 в количестве 2 штуки. 7. Бухгалтерские программы, сетевой экран, proxy сервер и др. утилиты. Это необходимый минимум, который обошелся бы компании в сумму, превышающую $150 тысяч. Директор посмотрел на свою новую Audi A4, которая стоит дешевле, чем необходимый софт, и сказал, что компания просто не в состоянии выделить такие деньги. Нужно как-то экономить. Надо, значит надо. Пришлось покупать только половину необходимых программ, а все остальные остались пиратскими до лучших времен. Я так и не застал перехода на лицензионные программы, потому что уволился и переехал в Питер, поэтому не знаю, потратил ли директор необходимые $150 или нет. А ведь это была небольшая компания с численностью компьютеров в 100 штук. А что говорить о больших компаниях, где бюджет программного обеспечения может исчисляться миллионами долларов. Действительно, глядя на необходимые для легальной жизни деньги, у любого человека глаза округляются, а челюсть приходиться поддерживать, дабы она не разбилась об пол. И это только первоначальные затраты, а дальше будет поддержка, переходы на новые продукты, продление лицензий для антивирусов и т.д. Нет, платить конечно надо, и это вполне нормально, но нужно подходить к этому вопросу разумно. ОС Linux помогает сэкономить достаточно большие средства. Давайте рассмотрим, как можно максимально безболезненно перейти на Linux, чтобы не пришлось продавать последнюю Audi, чтобы выйти из тени.
Джентльменский набор Перед непосредственным переходом на другую платформу, необходимо четко спланировать свои действия и тщательно подготовиться. Большинство из нас любит действовать нахрапом, т.е. решились, поставили, а потом решаем проблемы. Чтобы свести проблемы к минимуму, необходимо заранее все продумать. Первое, с чего стоит начать - это создать табличку, которая будет состоять из трех колонок: имя и должность пользователя, конфигурация компьютера и необходимые программы. Вообще-то, подобная табличка должна существовать у любого администратора, который содержит свою сеть под контролем и в чистоте. При миграции на Linux, вторая колонка не особо важна, потому что большинство дистрибутивов будет работать даже на стареньких компьютерах, но она может пригодиться, и об этом мы еще поговорим. Необходимые пользователю программы, помогут определить, есть ли замена в Linux для данной программы. Если для всех программ есть соответствующие аналоги, то переход может оказаться не за горами. Очень часто, секретари работают на компьютерах, на которых установлена только операционная система и офисный пакет, для набора документов. Устанавливать на такой компьютер Windows Vista в сочетании с MS Office – излишнее расточительство денег. Такой компьютер можно без проблем переводить на любой дистрибутив Linux и установить на него OpenOffice. Да, OpenOffice обладает меньшими возможностями, но вполне достаточными, для работы секретаря.
Дистрибутив Дистрибутивов открытых систем очень много. Только одних вариаций на тему ОС Linux можно насчитать несколько десятков, а ведь есть еще и BSD системы, которые также открыты и их нельзя сбрасывать со счетов. Что выбрать? Выбор достаточно сложный, но он должен основываться на следующих факторах: 1. Поддержка оборудования. Да, прошли те времена, когда любое нестандартное оборудование не определялось системой. В настоящий момент слабые производители обанкротились или перешли под крыло больших компаний, да и большинство из них уже не игнорирует открытые системы и своевременно выпускают необходимые драйвера. На наш взгляд, наилучшая поддержка реализована в Linux, и ее поддерживают большинство производителей. Как не прискорбно, но BSD системы некоторые продолжают игнорировать. Такие дистрибутивы как RedHat, SUSE и Fedora Core поставляются с богатым набором драйверов и на большинство компьютеров установятся без каких либо проблем. На всякий случай, следует проверить, созданную заранее табличку с конфигурацией всех компьютеров с требованиями и возможностями ОС. 2. Для открытых ОС существует множество программ, как бесплатных, так и с открытым исходным кодом. Конечно же, вам будет намного проще, если дистрибутив уже будет включать весь необходимый софт. Это значительно упростит начальную установку и ввод в эксплуатацию. Все крупные производители на данный момент включают максимально возможный набор программ и при выборе все тех же RedHat, SUSE и Fedora Core у вас не должно возникнуть проблем. 3. Не забываем и про поддержку. Несмотря на то, что в Интернете можно найти что угодно, я бы не стал пренебрегать поддержкой производителя и будет лучше, если ее вам предоставят на родном языке. Если вы считаете также, то обязательно посмотрите в сторону ASPLinux. Этот дистрибутив построен на технологиях Redhat и полностью с ним совместим. При этом он уже
давно обладает хорошей локализацией и отличной поддержкой. В данном случае, выбор ASPLinux – является моим личным предпочтением и некоторые могут со мной не согласиться. Но мы и не собираемся навязывать свое мнение. Выбор всегда остается за вами.
Пионер и где-то даже законодатель моды на рынке Linux - Redhat
Бухгалтерия В нашей стране бухгалтерия в большинстве случаев работает на 1C бухгалтерии. Но даже если у вас установлена другая программа, то не удивлюсь, если она будет также реализована только для платформы Windows. Хорошего решения для ОС Linux мы на данный момент не видели, поэтому этот сектор переводить на другую платформу проблематично и не имеет смысла. Да, можно установить Linux и выполнять программу 1С под эмулятором, но надежность от этого не вырастит, а скорей всего упадет. Ошибки в самой программе накладываются на проблемы эмуляции и в результате сбои могут происходить намного чаще. На данный момент, я бы не рекомендовал переводить бухгалтерию на другие платформы, по крайней мере, пока не появиться полноценных рабочих версий для Linux. Есть еще один вариант решения проблему – установить Linux и запускать Windows для работы с бухгалтерией из под виртуальной машины. Здесь есть одно преимущество – если бухгалтеру
необходим офисный пакет, то можно сэкономить и использовать OpenOffice, который входит в состав большинства дистрибутивов Linux. Виртуальные машины работают достаточно стабильно, но съедают драгоценное процессорное время и все равно требуют покупки лицензии на Windows, который вы будете использовать. Выгода минимальна. Если не хотите покупать MS Office, то можно обойтись OpenOffice под Windows, а переводить весь компьютер не имеет смысла.
ASPLinux Server можно легко настроить в качестве сервера для сетевой версии 1С. Этот дистрибутив прошел соответствующую сертификацию.
В серверной версии "1С Предприятие" версии 8.1 должна появиться работа под Linux с бесплатной базой данных PostgreSQL. Если перевести сервер под Linux, то это уже серьезная экономия денег, ведь Windows версия работает с MS SQL Server, который стоит недешево. Давайте посчитаем, сколько денег это сэкономит предприятию. ОС Windows Small Business Server 2003 стоит около $1500, а MS SQL Server в стандартной комплектации на пять клиентов стоит почти $2000. Перевод на Linux позволит сэкономить $3500. А если у вас достаточно крупное предприятие и требуется SQL Server Enterprise Edition, который стоит почти $15 000, то экономия будет еще больше.
Основная задача В любой компании должна быть какая-то определенная программа, с которой работают сотрудники. Если у вас все построено на 1С или другой программы стороннего разработчика, которая реализована только для Windows, то столкнетесь с теми же проблемами, что мы рассматривали для бухгалтерии. В этом случае, переход не имеет смысла, и вы оказываетесь заложниками Windows. Если же вы используете программу собственной разработки, то тут уже все немного проще. Если программа написана на С++ или Delphi, то я бы порекомендовал перевести ее на Java. В Европе и особенно в США этот язык сейчас очень популярен и останется таким в ближайшие
годы. В 2005-м году, Java обошел по популярности даже С и С++, которые долгое время держали пальму лидерства. С чем связана такая популярность? На это есть множество причин: 1. Простота и удобство языка; 2. Поддержка компонентной модели; 3. Платформа J2EE удобна для разработки корпоративных приложений; 4. Независимость от платформы.
Среда разработки JBuilder почти также проста, как и Delphi, а если вы используете С++, то миграция переход на Java будет еще проще
Это четыре основных признака, которые на наш взгляд позволили Java получить нынешнюю популярность, а с выходом 5-й версии, популярность будет расти. Самый важный для нас фактор мы поставили под 5-м номером – это независимость от платформы. Программа написанная на 100% Pure Java будет работать на Windows, Linux, Maс и других платформах без каких-либо изменений, и при этом, все будет выглядеть одинаково, а надежность не пострадает. Это очень удобно, особенно, когда в вашей сети используются компьютеры разных платформ, ведь пользователи Linux и Windows будут использовать одну и ту же программу и будут иметь одинаковый интерфейс. Если что-то пойдет не так, то всегда можно будет вернуться в MS Windows без особых проблем и за минимально возможное время. Итак, если ваша основная программа, написана на Java, то никаких проблем с переходом не возникнет. Если нет, то я бы порекомендовал бы переписать программу. Да, переписывание отнимет очень много времени и нервов (особенно, если у вас большая компания и учет требует
очень большого количества нюансов), но зато вы станете независимыми от платформы и можете мигрировать куда угодно и когда угодно.
WEB интерфейс Если вас не устраивает Java или вы просто не любите этот язык, то можно посмотреть в сторону WEB интерфейса. С помощью таких языков как ASP, PHP, Perl в связке с HTML можно реализовать работу с корпоративной базой данных прямо из браузера. На мой взгляд, с точки зрения пользователя, такие программы будут менее удобны, зато работать будут везде, где есть браузер, хоть в карманном компьютере. Подобное решение я видел в одной из частных больниц. Там не требовалось особо сложных алгоритмов, и использовалась простая база данных для учета посетителей. Программист, которого попросили написать программу, знал только PHP и он справился со своей работой достаточно хорошо. Работать с базой данных оказалось не так уж и плохо. Но если вы собираетесь создавать что-то на PHP, вы должны учитывать, что на данных момент этот язык не может работать с потоками и не сможет использовать преимущества многоядерных архитектур. Возможно, этот недостаток будет исправлен в ближайшее время, но сейчас такая проблема существует.
Учеба Самое сложное в любом переходе – это убедить пользователей, что это им действительно нужно. Мне несколько раз приходилось вводить новые программы, и каждый раз я встречался с большим сопротивлением. Те, кто внедрял что-то новое, поверх существующего, меня поймут. Большинство пользователей воспринимают все новое в штыки, пусть даже оно в сто раз лучше и удобнее. Операторы, которые тупо вводят какие-то данные в компьютер, банально привыкают к определенному интерфейсу, и даже если он работает с ошибками и не позволяет выполнять поставленные задачи, никто не хочет что-то менять. Привычка пользователей – самый большой барьер. Чтобы преодолеть барьер привычки, необходимо обучать пользователей и чем-то заинтересовывать их. Можно пойти на какие-то хитрости, например, показать, что в Linux есть множество интересных игр, в которые можно играть в перерывах. Когда переход завершиться, игры можно удалить. Да, это жестоко, но воевать приказами бесполезно. Даже если начальство жестко прикажет всем переходить на новую версию программы, все согласятся, но каждые пять минут будут возмущаться и ругать всех программистов и администраторов. Учеба позволяет заинтересовать пользователей в изучении нового и смягчит переход. Если каждый день хотя бы по часу выделять на обучение, чтобы сотрудники фирмы знали Linux и OpenOffice лучше, чем MS Windows и MS Office, то все сами захотят побыстрее перейти, а сама миграция пройдет максимально гладко.
Переход Когда вы определились с программами и обучили пользователей, можно начинать плавный переход. Переводить компьютеры необходимо постепенно и по отделам или должностям. Например, первыми на переход могут пойти секретари. Чаще всего у них простые программы, но они самые сложные в обучении. Нет, я не имею ввиду пол и цвет волом. Блондинки тут не причем. Просто это мое личное наблюдение. Не стоит пытаться перевести всех сразу, это слишком большой объем работы.
Между переходами необходимо делать небольшие перерывы, чтобы пользователи, которые перешли на Linux успели привыкнуть к новому интерфейсу и к новым программам. Учеба никогда не заменит реальную работу, поэтому после начала реальной эксплуатации, будет возникать множество вопросов, на которые вы должны быть готовы ответить, точнее сказать, у вас должно быть свободное время, чтобы успевать помогать. В настоящее время, появляются виртуальные машины, которые аппаратно поддерживают виртуализацию, но далеко не каждый процессор поддерживает виртуализацию аппаратно. В любом случае, на первых порах, можно запускать Linux в виртуальной машине, чтобы пользователи привыкали, а если возникают проблемы, то всегда можно переключиться в Windows и через секунду уже работать со старыми и привычными программами.
Итого Программы с открытым кодом типа ОС Linux, OpenOffice и т.д. позволяют сэкономить деньги на этапе внедрения, потому что не требуют начальных вложений на покупку лицензий и коробочных продуктов. ОС Linux безопаснее, особенно потому, что для нее практически нет вирусов. Но с другой стороны, они требуют большей квалификации с точки зрения сопровождения. Да, инструменты управления системой становятся все проще и проще, но не смотря на это, Windows считается более простой, да и большинство пользователей и администраторов работает именно с продуктами от MS. Судя по большинству сайтов, где можно найти предложения по работе, администраторы Linux ценятся дороже, особенно это касается Америки. Если посмотреть на monster.com, то программисты Java и С/С++ под ОС Linux также стоят дороже. Мне кажется, это связано с тем, что тут требуется большая квалификация (ну нет там таких мастеров, как в Windows) и количество специалистов в этой области меньше. Чтобы увидеть разницу в количестве специалистов, можно посмотреть, сколько курсов преподают по Windows, а сколько по Linux. Спрос на продукты Microsoft на данный момент выше. Но в нашей стране все может измениться, когда еще сильнее ужесточиться контроль над лицензионными программами.
By Фленов Михаил aka Horrific E-mail: info@vr-online.ru
Без рамки
AnklaV, или Лес там ====>
AnklaV, или Лес там ====> -----------*** День 12 *** "Сегодня я стану богом" Он: Ладно, всем спасибо, все свободны. Виктор: Стой! Он: Да пошёл ты. Пошли вы все, я устал. (выбрасывается из окна) ... Она (играет в NFS, комментарии): Блять... какая неприятность... А... извините, промахнулась. Ничего-ничего, я не отстаю... А, это спринт, ну ты глянь... Вот так всегда... Ах, ты ж... Блять, ну почему на самом старом... Сука какая, наебал... Ой, мамочки... Выиграла... Да, выиграла... Несмотря на происки врагов. Даже что он меня развернул на повороте... Чё-то дали...
-----------*** День 11 *** "Стены" Он: Твою мать! Что же творится! ... Юля: Черти! Пошли все вон!!! Аааа, нет, нет, нет, нет, всем тихо... Мы общаемся... Даааа... (падает на кровать и истерически смеётся) ... Портрет змеи на стене: Когда-то это должно было случиться. Декорации были расставлены в самом начале, занавес был поднят, а куклы почти сыграли свои роли, представление почти завершилось. Отсутствие режиссёра им не помеха, они прекрасно справляются сами. Это странное, но не лишённое интереса, явление, когда пьеса сама себя развивает. Надо только начать, дать ей жизнь и начальные условия, дальше она сама себя разовьёт, возвысит и опустит на самое дно... Многие верят в чью-то волю, в чью-то направляющую руку, в доброе и злое начало, и совершенно не допускают варианта, что, может быть, они сами являются этой рукой. При определённых условиях, конечно же. Безусловно, можно решать за них всё, писать сценарии, репетировать, оттачивать мастерство. Но куда как приятнее смотреть на экспромт: задаёшь тему и пожинаешь плоды. Но в данном случае даже темы не было, ибо всё это чистейшей воды работа участников спектакля. Главные и второстепенные герои определяются по ходу дела... Впрочем, я заговорился, прошу меня простить, мы продолжаем. (застывает)
-----------*** День 10 *** "Круг"
Он: Я скучаю. Она: Я тоже. Он: Встретимся сегодня? Она: Да. ... Он: На самом деле я боюсь потерять тебя. Она: :) Это неизбежно. Прими это как должное. Так будет проще жить. ... Он: Почему ты живёшь так далеко? Почему время наших встреч ограничено полуночью? Она: :( ... Она: Я вижу, что тебя это напрягает, ты расстраиваешься. Он: Я не могу жить так, как ты живёшь. Я хочу работать, а не праздно шататься по улицам, спать, когда захочется, слушать музыку и пить вино. Нет, я этого хочу, но это единственное, чем ты занимаешься. Ты же больше ничего не делаешь. Безусловно, тебе скучно. Безусловно, у тебя нету целей в жизни, ты же не хочешь работать. ... Абстрактный знакомый: Ну как Она? Он: ХЗ. Я не в курсе. ... Он: (чуть позже, сидит один в своей комнате) Она лучше всех. Только я не считаю, что должен выставлять наши с ней отношения напоказ. Это наша личная жизнь. Какой смысл обсуждать её с кем-то? Она: (на другом конце города, одна в своей квартире) Просто есть несколько людей, которым я говорила "нет". Они мне дороги, и я не хочу терять их. Но они не понимают слова "нет" и живут в надежде, пусть и призрачной, пусть даже я на каждое их выражение чувств отвечаю твёрдым отказом, но они не останавливаются. Это чувство должно перейти в дружбу. Он: Я знаю. Но я молчу не из-за этого. Просто не считаю нужным делать из этого публичное зрелище. Мне важна ты, а не мнение окружающих о нас и наших отношениях. Она: Люблю тебя. Он: Взаимно.
-----------*** День 9 *** "Отторжение" Юля: А ты не боишься конкуренции? Он: Нет. (в сторону) Ты же ещё ребёнок, а туда же. Юля: А ко мне муж в последнее время охладел. Я с ним пыталась поговорить, но он как-то всё время занят, всё ему не до того. Он, конечно, держится молодцом. Делает вид, как будто нам не грозит скорое и продолжительное расставание. ... Она: Конечно, он её посылает. Присмотрелся к ней и всё понял. ... Он: Не знаю что и думать. По натуре своей я хочу одиночества... Всегда. Даже её присутствие мне в тягость. Нет... Не в тягость. Я не могу жить без неё. Когда она рядом, мне кажется, что всё будет хорошо, даже если всё из рук вон плохо. Я всем сердцем не хочу, чтобы она уходила. Хотя это неизбежно. Но другая моя сторона требует одиночества для создания рабочего настроения. Поэтому я работаю, когда она рядом, когда она спит или чем-то занята. Это позволяет быть рядом с ней и одновременно получать покой, необходимый для работы. Кто-то: Делай, что считаешь нужным. Родители: Просто помни, что ты наш сын.
-----------*** День 8 *** "Я и моя тень" Мать: Если ты боишься потерять её, то не бойся - ты её не потеряешь... Ты никого не потеряешь. (смеётся) Даже... даже... Вот скажу тебе, только без этого... (делает непонятный круговой жест руками) Любая девка всё бы отдала за такого парня! Он: Да уж. Не потеряю. Эти призраки прошлого и по сей день всплывают. Мать: На самом деле у тебя много достоинств. Нет, серьёзно. Не знаю, как ты там себе считаешь, но у тебя много достоинств. Он: Ты мне льстишь.
-----------*** День 7 *** "СМС-ки" Знакомая (смс): Ты хотел бы, чтобы у тебя были дети?
Он (смс): Быть может когда-то и захочу. Знакомая (смс): Ходить по краю, смотреть, как песок сыпется из-под твоих ног - лучшее, когда влюблён. Он (смс): Мне это знакомо. Даже более, чем когда-либо. Знакомая (смс): Я очень рада за тебя. Так как, несмотря ни на что, это самое волшебное чувство. ... Артём (смс): Где ты? Куда пропал? Он: Пью. Шутка. Но ему ничего писать не буду. ... Юля (смс): Ну как там дела? Как народ? Как сам? Расскажи, а то мне скучно тут без вас. У меня тут потихоньку всё. Он (смс): Не знаю. Я ушёл оттуда. Юля (смс): Почему? Что-то случилось? А Она? Он (смс): Ничего не случилось. :) Просто надоело заниматься ерундой. Пора жить в реале: работа, учёба, личная жизнь. Всё в норме. Юля (смс): Жалко, что уходишь. Я к тебе привязалась :). Как Она на это смотрит? Она тоже уходит? Он (смс): Она в курсе и согласна. Уходит или нет - покажет время. ... Он (смс): Ты знаешь, что ты лучшая? Она (смс): Теперь знаю :) Я люблю тебя. -----------*** День 6 *** "Я. Мой монолог" Он: Ты знаешь, у меня такое странное чувство, какое я не испытывал никогда. Какая-то смесь радости, отчаяния и безразличия. Не знаю к чему бы это, но, видимо, это есть следствие недавних дум. Недавно мне показалось, что пути назад нет, что сожжены мосты, и что я перешагнул через какую-то грань. Не то, чтобы я жалел об этом, но просто я осознал, что не хочу, да и, скорее всего, не могу возвращаться. Не хочу снова быть один... ...
Он: Мне скучно жить с 16 лет. Я не вижу смысла, не вижу, ради кого стоит жить. По какой-то странной прихоти судьбы я нашёл человечка, ради которого стоит жить, с которым стоит что-то делать в этой жизни. Этот человечек меня вдохновляет и наполняет мою жизнь смыслом. Но по той же неумолимой прихоти судьбы мне противно человеческое общество. А, значит, и её общество мне тоже противно. Это не самонастройка, я констатирую факты. Мне она отчего-то кажется такой беспомощной, ни на что неспособной. Почему-то она кажется мне суккубом... Нахрена мне нужно тащить на себе кого-то? ... Он: Что мне не нравится?.. Мне в принципе чуждо то общество, в котором живёшь ты. В целом. Я к нему не привык. Я не говорю, что оно плохое, я говорю, что оно мне не привычно и что мне тут многое в новинку. Например, я не привык, что, скорее всего, я встречусь вновь с теми незнакомыми людьми, которых я видел на улице. В Москве с этим проще - это как огромный муравейник, где ты уверен, что проходящего мимо человека ты видишь первый и последний раз в жизни. Там можно творить всё - тебя не запомнят; тебя могут осудить, но кого это волнует, если ты этого человека больше не увидишь? Там есть толпа, серая толпа, частью которой ты сам можешь стать. А тут всё иначе - тут тебя запоминают, даже в небольшой степени следят за твоей жизнью. Тут выставление чувств напоказ чревато тем, что тебя запомнят, и то будут люди, которых ты потом будешь встречать и работать с ними. Что меня ещё напрягает? Компании. Я не очень люблю компании в принципе, и, если дома сбор компаниями редок, то тут это, как мне кажется, неотъемлемая часть жизни, ибо в ином случае тут было бы невыносимо скучно. Но больше всего я страдаю от разницы мышления. Я пытаюсь изменить свой образ мышления, чтобы быть с вами в одной струе, но мне это даётся нелегко, и получается только методом проб и ошибок. Причём ошибки я переживаю тяжело; мне кажется, что каждый мой промах сильно разделяет нас, и что я не компенсирую свои промахи своими удачами. Мне кажется, что я тебя разочаровываю.
-----------*** День 5 *** "Не бойся" Он: За что я люблю тебя? Она: Тебе просто делать нечего. (смеётся, обнимает) ... Он: Ведь надо работать. Ты сейчас ведёшь паразитический образ жизни. Мама не сможет долго присылать деньги. Ты собираешься работать сама? Исправлять ситуацию? Она: Если бы хотела, давно бы исправила. Он: Но ты ведь паразит. Смерть хозяина - и ты без средств к существованию. Она: Знаю. Он: То есть ты не собираешься ничего менять? Она: Меня пока всё устраивает. ...
Она: Зай... По поводу нашего разговора. Обо мне. Не волнуйся за себя. Я люблю пока есть возможность, а возможности у нас ещё неделя. Он: Я знаю.
-----------*** День 4 *** "Хм..." Он: Она ведь слушает меня. Как же всё это началось... ... Друг: Уходи ты оттуда, это зло. Пора бы уже стать реалистом, а не пофигистом. Надо остепениться, жить по средствам, пойти на работу. Тебе же уже 25 лет. Она: Ой, да ладно, это ты меня такой сделал. Друг: Чё? Она: Да, ты. Я до тебя была примерной дочкой, прямо образец для подражания. Друг: Ну ты сравнила, нам тогда было по 18 лет... 17. И с тех пор я вырос, остепенился, но только не ты. Она: (в сторону) Он меня оскорбляет. Он: Он прав.
-----------*** День 3 *** "Она и Он" Она: Я скоро уезжаю, тут уже нет смысла оставаться. Он: Я поеду с тобой. Она: Я боюсь тебя разочаровать. Я боюсь, что надоем там тебе за те несколько дней. Он: Время покажет. ... Он: Что ты возьмёшь с собой отсюда? Я имею ввиду - чего уникального? Она: Китайское вино с вишнями. И хлебные палочки. Он: А как получилось, что у тебя столько коробок? Их тут штук 10-12. Ты с ними приехала?
Она: Нет, я приехала с одним чемоданом и котом, а всё остальное наприсылала мне мама. ... Он: Иногда я долго не говорю, что думаю. Я застенчивый просто пипец. Она: (с сарказмом) Да, я заметила. Готов целоваться на улице... Да, застенчивый. Он: Я делаю то, что мне разрешили делать. Где - это второй вопрос.
-----------*** День 2 *** "День второй" Он: (сам себе) Почему-то меня все знакомые, причём не только девушки, имеют тенденцию прятать от остальных. От родителей, знакомых, коллег... Всегда прячут... Намеренно не поднимают трубки, если я рядом, а если и поднимают, то говорят что-то отвлечённое, но никак не говорят, что со мной. Врут. Всё время паникуют, что нас застанут вместе. Хотя очень часто сами зовут меня, тянутся. Я что, такой особенный? ... Она: Я та ещё лентяйка... Я приехала сюда учиться и работать... А ещё я сволочь и зараза. Мне так все говорят, кто знает меня достаточно долго... Я не хочу жить в реальном мире, там нет смысла. Он: Не согласен.
-----------*** День 1 *** "Выходи за меня" Он: Выходи за меня. Она: Я согласна.
-----------*** День 13 *** "Пейзаж" Кто-то: Что это было-то вообще? Человек в белом халате: Самоубийство это. Причём, второе за два дня. Не спасли на этот раз. (складывает вещи в сумку и быстро уходит)
Проходящая мимо девушка: (очень тихо) Это должна была сделать я, а не он. ... Юля: Почему они все такие счастливые? Почему я такая обделённая? (украдкой смахивает слезу) Слава: С тобой скучно, ты видишь то, что хочешь видеть. Юля: Чего? Слава: Юль, я не в духе сейчас. Да и вообще нет желания объяснять тебе случившееся. Каждый человек творит собственную судьбу. Так или иначе, но мы оба сделали свой выбор. Не стоит из-за него огорчаться. ... Портрет змеи на стене: Забавно получилось. Маска тигра: Да, было занятно смотреть. Зрителям, как я посмотрю, тоже понравилось. Парня только жалко. Портрет змеи на стене: Да хрен бы с ним, это ж банальщина. Сколько таких вот было, а сколько ещё будет. Маска тигра: Эхъ... Почему-то мне уже всё равно. Скучно даже как-то. Портрет змеи на стене: Ага, представление затянулось. Пора заканчивать. Повторим завтра? (занавес закрывается)
END 24.08.2007
by Neon_Kaligula aka Мартынов Алексей