Отправляет email-рассылки с помощью сервиса Sendsay

Программирование и др.

  Все выпуски  

Программирование в Linux с нуля - Выпуск 3


Информационный Канал Subscribe.Ru

Программирование в Linux с нуля. Выпуск 3.

1. Предисловие

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

2. Программа

2.1. Описание

Воспользуемся программой из прошлого выпуска. Модернизируем ее до чистого C++ и разобьем на три части, поместив каждую такую часть в отдельный файл. Назовем эти файлы main.cpp pswgen.h и pswgen.cpp.

2.2. Файл main.cpp


#include "pswgen.h"

int main ()
{
 pswgen p (3, 2, 0);
 p.outp ();

 return 0;
}

2.3. Файл pswgen.h


class pswgen
{
 private:
  int buf_size;
  int latest_item;
  int top_index;
  int bottom_index;

  char* dict;
  char* buffer; 
  
 public:
  pswgen (int, int, int);
  ~pswgen();
  
  int nextp (int);
  void outp ();
};

2.4. Файл pswgen.cpp


#include <iostream>
#include <cstring>
using namespace std;

#include "pswgen.h"

pswgen::pswgen (int a, int b, int c)
{
 dict = new char [3];
 buffer = new char [buf_size];

 buf_size = a;
 top_index = b;
 bottom_index = c;

 strcpy (dict, "a-z");

 latest_item = 1;
}

pswgen::~pswgen ()
{ 
 delete [] buffer;
 delete [] dict;
}

void pswgen::outp ()
{
 memset (buffer, dict[bottom_index], buf_size); 

 do {
  cout << buffer << '\n';
 } while (!nextp (buf_size));
}

int pswgen::nextp (int n)
{
 int i; 
 if (n == buf_size) {
  if (buffer[buf_size-1] == dict[bottom_index])  
   { buffer[buf_size-1]++; return 0; }
         else  { return nextp (buf_size-1); }
 }
 
 if (buffer[n] == dict[top_index]) {  
  for (i = n; i < buf_size; i++) 
   { buffer[i] = dict[bottom_index]; }
  
  if (n != bottom_index) { return nextp (n-1); } 
  
  else { return latest_item; }  
 } 
 
 buffer [n]++;
 return 0;
}

2.5. Компиляция и сборка

Сначала откомпилируем файлы main.cpp и pswgen.cpp. Затем полученные объектные файлы main.o и pswgen.o соберем в один исполняемый файл pswgen и запустим нашу программу. Замечание: символ #, указывающий приглашение командной строки я заменил на $.


$ g++ -c main.cpp
$ g++ -c pswgen.cpp
$ g++ -o pswgen main.o pswgen.o
$ ./pswgen > passwords.txt

В третьей строке мы поручили компилятору вызвать линковщик. Аргумент опции -o указывает имя исполняемого файла.

В дополнение. У вас возникало желание объединить все эти команды в один скрипт? Не торопитесь делать это, а лучше дождитесь следующего выпуска рассылки.

3. Теория

3.1. КИС - клиент-интерфейс-сервер

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

Клиент - это нечто, что пользуется услугами сервера в соответствии с некоторым интерфейсом (протоколом). Протокол (интерфейс) определяет "правила игры", организует взаимопонимание между клиентом и сервером. Сервер через интерфейс предоставляет свои услуги любому числу клиентов. Эта система укоренилась в компьютерных сетях, в экономике, в жизни, а главное (для нас) - в репозиториях. Репозиторий - это каталог, в котором содержатся все файлы программного проекта. В нашем конкретном примере можно сказать, что проект pswgen использует репозиторий, содержащий файлы main.cpp pswgen.h pswgen.cpp pswgen и passwords.txt. Все программы, которые мы будем писать, будут расчленяться на клиенты интерфейсы и серверы на уровне исходных кодов, т.е. каждый исходный файл будет являться или клиентом или интерфейсом или сервером.

Рассмотрим пример (hello.c):


#include <stdio.h>

int main (void)
{
 printf ("%s\n", "Hello World!");
 return 0;
}


Узнаете? Где же здесь клиент, где интерфейс и где сервер? Клиент - файл hello.c, интерфейс - файл /usr/include/stdio.h, сервер - файл /usr/lib/libc.so (стандартная библиотека языка C). Забегая вперед скажу, что библиотеки - это особый вид объектных файлов. Библиотеки создают тогда, когда один или несколько объектных файлов-серверов могут быть полезны другим программам-клиентам.

Теперь рассмотрим нашу программу. Здесь main.cpp (main.o) - клиент сервера pswgen.cpp (pswgen.o), использующие интерфейс pswgen.h. Однако pswgen.cpp (pswgen.o) также является клиентом, но уже для других серверов и через другие интерфейсы. Наш пример показывает, что существует также иерархия серверов, на верхушке которой стоит BIOS компьютера.

Замечание: не путайте BIOS (Basic Input-Output System) с BIOS Setup Utility (программа настройки BIOS).

Один клиент может пользоваться услугами нескольких серверов. Для этого необходимо, чтобы клиент "знал" интерфейсы этих серверов. В нашем случае клиент "узнает" интерфейс посредством директивы #include.

Всякий раз, когда вы вызываете какую-нибудь функцию, вы пользуетесь услугами сервера (код функции) через интерфейс (объявление функции).

Рассмотрим пример (anyfile.c):


/*начало интерфейса 1*/
void anyfunction1 (void); /*объявление функции anyfunction1()*/
/*конец интерфейса 1*/

/*начало интерфейса 2*/
void anyfunction2 (void); /*объявление функции anyfunction2()*/
/*конец интерфейса 2*/

/*начало клиента*/
int main (void)
{
 anyfunction1 ();
 anyfunction2 ();
 return 0;
}
/*конец клиента*/

/*начало сервера 1*/
void anyfunction1 (void)
{
    /*код функции anyfunction1()*/
}
/*конец сервера 1*/

/*начало сервера 2*/
void anyfunction2 (void)
{
    /*код функции anyfunction2()*/
}
/*конец сервера 2*/



Этот пример показывает, что можно сервер, интерфейс и клиент "запихнуть" в один исходный файл. Для небольших программ это допустимо. Что же получится с проектом побольше:
1. Изменение одного сервера или одного клиента потребует перекомпиляции всего файла. Компиляция - долгий процесс. Я участвовал в создании проекта, полная компиляция которого на среднестатистической машине занимала 19 минут. А если исправить один файл, то в большинстве случаев можно откомпилировать только его, затем просто заново собрать проект (процедура сборки не такая долгая).
2. Большие файлы неудобно читать. В них легко запутаться.
3. В одном файле очень трудно (хотя это возможно) разместить исходный код на разных языках программирования.
4. Если над проектом работает несколько человек, то использование одного исходного файла становится вообще недопустимым.

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

Заключение

Материал этого выпуска очень важен для дальнейшего обучения. Если возникнут вопросы, пишите мне на nnivanov@mail.ru. В следующем выпуске будем учиться работать с GNU-утилитой make.

Всегда ваш. Николай.
Рассылки Subscribe.Ru
*nix project - новости из мира unix-систем! (ежедневная)

http://subscribe.ru/
http://subscribe.ru/feedback/
Подписан адрес:
Код этой рассылки: comp.soft.prog.linuxp
Отписаться

В избранное