KnigaRead.com/

Нейл Мэтью - Основы программирования в Linux

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Нейл Мэтью, "Основы программирования в Linux" бесплатно, без регистрации.
Перейти на страницу:

   } else {

    fprintf(stderr, "%s", mess_ret.error_text);

   }

  } else {

   fprintf(stderr, "Server failed to respondn");

  }

 } else {

  fprintf(stderr, "Server not accepting requestsn");

 }

 return(ret_val);

}

5. Далее приведен исходный текст функции read_one_response, которая используется для устранения дублирующегося программного кода.

static int read_one_response(message_db_t *rec_ptr) {

 int return_code = 0;

 if (!rec_ptr) return(0);

 if (start_resp_from_server()) {

  if (read_resp_from_server(rec_ptr)) {

   return_code = 1;

  }

  end_resp_from_server();

 }

 return(return_code);

}

6. Остальные подпрограммы get_xxx, del_xxx и add_xxx реализованы аналогично функции get_cdc_entry и приводятся здесь для полноты картины. Сначала функция для извлечения дорожек компакт-диска.

cdt_entry get_cdt_entry(const char *cd_catalog_ptr,

 const int track no) {

 cdt_entry ret_val;

 message_db_t mess_send;

 message_db_t mess_ret;

 ret_val.catalog[0] = '';

 mess_send.client_pid = mypid; mess_send.request = s_get_cdt_entry;

 strcpy(mess_send.cdt_entry_data.catalog, cd_catalog_ptr);

 mess_send.cdt_entry_data.track_no = track_no;

 if (send_mess_to_server(mess_send)) {

  if (read_one_response(&mess_ret)) {

   if (mess_ret.response == r_success) {

    ret_val = mess_ret.cdt_entry_data;

   } else {

    fprintf(stderr, "%s", mess_ret.error_text);

   }

  } else {

   fprintf(stderr, "Server failed to respondn");

  }

 } else {

  fprintf(stderr, "Server not accepting requestsn");

 }

 return(ret_val);

}

7. Далее две функции для вставки данных, первая для добавления элемента каталога, а вторая — дорожек в базу данных.

int add_cdc_entry(const cdc_entry entry_to_add) {

 message_db_t mess_send;

 message_db_t mess_ret;

 mess_send.client_pid = mypid;

 mess_send.request = s_add_cdc_entry;

 mess_send.cdc_entry_data = entry_to_add;

 if (send_mess_to_server(mess_send)) {

  if (read_one_response(&mess_ret)) {

   if (mess_ret.response == r_success) {

    return(1);

   } else {

    fprintf(stderr, "%s", mess_ret.error_text);

   }

  } else {

   fprintf(stderr, "Server failed to respondn");

  }

 } else {

  fprintf(stderr, "Server not accepting requestsn");

 }

 return(0);

}


int add_cdt_entry(const cdt_entry entry_to_add) {

 message_db_t mess_send;

 message_db_t mess_ret;

 mess_send.client_pid = mypid;

 mess_send.request = s_add_cdt_entry;

 mess send.cdt_entry data = entry_to_add;

 if (send_mess_to_server(mess_send)) {

  if (read_one_response(&mess_ret)) {

   if (mess_ret.response == r_success) {

    return(1);

   } else {

    fprintf(stderr, "%s", mess_ret.error_text);

   }

  } else {

   fprintf(stderr, "Server failed to respondn");

  }

 } else {

  fprintf(stderr, "Server not accepting requestsn");

 }

 return(0);

}

8. В заключение две функции для удаления данных.

int del_cdc_entry(const char *cd_catalog_ptr) {

 message_db_t mess_send;

 message_db_t mess_ret;

 mess_send.client_pid = mypid;

 mess_send.request = s_del_cdc_entry;

 strcpy(mess_send.cdc_entry_data.catalog, cd_catalog_ptr);

 if (send_mess_to_server(mess_send)) {

  if (read_one_response(&mess_ret)) {

   if (mess_ret.response == r_success) {

    return(1);

   } else {

    fprintf(stderr, "%s", mess_ret.error_text);

   }

  } else {

   fprintf(stderr, "Server failed to respondn");

  }

 } else {

  fprintf(stderr, "Server not accepting requestsn");

 }

 return(0);

}


int del_cdt_entry(const char *cd_catalog_ptr, const int track no) {

 message_db_t mess_send;

 message_db_t mess_ret;

 mess_send.client_pid = mypid;

 mess_send.request = s_del_cdt_entry;

 strcpy(mess_send.cdt_entry_data.catalog, cd_catalog_ptr);

 mess_send.cdt_entry_data.track_no = track_no;

 if (send_mess_to_server(mess_send)) {

  if (read_one_response(&mess_ret)) {

   if (mess_ret.response == r_success) {

    return(1);

   } else {

    fprintf(stderr, "%s", mess_ret.error_text);

   }

  } else {

   fprintf(stderr, "Server failed to respondn");

  }

 } else {

  fprintf(stderr, "Server not accepting requestsn");

 }

 return(0);

}

Поиск в базе данных

Функция поиска по ключу компакт-диска сложнее. Пользователь этой функции рассчитывает вызвать ее один раз для начала поиска. Мы удовлетворили его ожидания в главе 7, задавая параметр *first_call_ptr равным true при первом вызове функции, и функция в этом случае возвращает первое найденное совпадение. При последующих вызовах функции поиска указатель *first_call_ptr равен false и возвращаются дальнейшие совпадения, по одному на каждый вызов.

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

Можно либо изменить алгоритм поиска, либо, как показано в приведенном далее программном коде, спрятать сложность в подпрограмме интерфейса. Данный код вынуждает сервер возвращать все возможные совпадения с искомым значением и затем сохраняет их во временном файле до тех пор, пока клиент не запросит их.

1. Эта функция не так сложна, как кажется, просто в ней вызываются три функции канала send_mess_to_server, start_resp_from_server и read_resp_fromserver, которые будут рассмотрены в следующем разделе.

cdc_entry search_cdc_entry(const char *cd_catalog_ptr,

 int *first_call_ptr) {

 message_db_t mess_send;

 message_db_t mess_ret;

 static FILE *work_file = (FILE *)0;

 static int entries_matching = 0;

 cdc_entry ret_val;

 ret_val.catalog[0] = '';

 if (!work_file && (*first_call_ptr == 0)) return(ret_val);

2. Далее показан первый вызов для поиска с указателем *first_call_ptr, равным true. Он немедленно приравнивается false, на случай, если вы забыли. Создается временный файл work_file и инициализируется структура сообщения клиенту.

if (*first_call_ptr) {

 *first_call_ptr = 0;

 if (work_file) fclose(work_file);

 work_file = tmpfile();

 if (!work_file) return(ret_val);

 mess_send.client_pid = mypid;

 mess_send.request = s_find_cdc_entry;

 strcpy(mess_send.cdc_entry_data.catalog, cd_catalog_ptr);

3. Теперь приводится проверка условий с тремя уровнями вложенности, заставляющая вызывать функции из файла pipe_imp.c. Если сообщение успешно отправлено на сервер, клиент ждет ответа от сервера. Пока считывания с сервера успешны, совпадения с искомой величиной возвращаются в work_file клиента и наращивается счетчик entries_matching.

 if (send_mess_to_server(mess_send)) {

  if (start_resp_from_server()) {

   while (read_resp_from_server(&mess_ret)) {

    if (mess_ret.response == r_success) {

     fwrite(&mess_ret.cdc_entry_data, sizeof(cdc_entry), 1, work_file);

     entries_matching++;

    } else {

     break;

    }

   } /* while */

  } else {

   fprintf(stderr, "Server not respondingn");

  }

 } else {

  fprintf (stderr, "Server not accepting requestsn");

 }

4. Следующая проверка ищет, есть ли совпадения с заданным значением. Далее вызов fseek переводит указатель в файле work_file на место записи следующей порции данных.

 if (entries_matching == 0) {

  fclose(work_file);

  work_file = (FILE *)0;

  return(ret_val);

 }

 (void)fseek(work_file, 0L, SEEK_SET);

5. Если это не первый вызов функции поиска для данного конкретного элемента, программа проверяет, были ли уже найдены совпадения. В заключение в структуру ret_val читается следующий совпадающий элемент. Предшествующие проверки гарантируют наличие совпадающего элемента.

 } else {

  /* не *first_call_ptr */

  if (entries_matching == 0) {

   fclose(work_file);

   work_file = (FILE *)0;

   return(ret_val);

  }

 }

 fread(&ret_val, sizeof(cdc_entry), 1, work_file);

 entries_matching--;

 return(ret_val);

}

Интерфейс сервера server.c

Если у клиента есть интерфейс для обращения к программе app_ui.c, серверу также нужна программа для управления (переименованной) программой cd_access.c, теперь cd_dbm.c. Далее приведена функция main сервера.

1. Начните с объявления нескольких глобальных переменных, прототипа функции process_command и функции перехвата сигнала для обеспечения чистого завершения.

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*