- 論壇徽章:
- 0
|
搜索數(shù)據(jù)庫(kù)
在CD關(guān)鍵字上的搜索比較復(fù)雜。函數(shù)的用戶希望一旦調(diào)用就啟動(dòng)一個(gè)搜索。我們?cè)诘?章通過(guò)將在第一次調(diào)用上的*first_call_ptr設(shè)置為
true并且函數(shù)返回第一個(gè)匹配結(jié)果來(lái)滿足這種需求。在接下來(lái)的搜索函數(shù)調(diào)用中,*first_call_ptr設(shè)置為false,從而會(huì)返回更多的匹
配,每次調(diào)用返回一個(gè)匹配結(jié)果。
現(xiàn)在我們已經(jīng)將程序分為兩個(gè)進(jìn)程,我們不能再允許搜索在服務(wù)器端一次處理一個(gè)實(shí)體,因?yàn)榱硪粋(gè)不同的客戶端也許會(huì)由服務(wù)器請(qǐng)求一個(gè)不同的搜索,而我們的搜
索仍在處理之中。我們不能使得服務(wù)器端為每一個(gè)客戶端單獨(dú)存儲(chǔ)搜索內(nèi)容(搜索已經(jīng)進(jìn)行到哪里),因?yàn)楫?dāng)一個(gè)用戶找到他們要找的CD關(guān)鍵值時(shí)或是客戶端出現(xiàn)
問(wèn)題,客戶端就可以簡(jiǎn)單的停止搜索。
我們或者可以改變搜索執(zhí)行的方式,或者是,正如我們?cè)谶@里所選擇的,在接口例程中隱藏復(fù)雜性。我們所做的就是使得服務(wù)器返回所有可能的搜索匹配,然后將他們存儲(chǔ)在一個(gè)臨時(shí)文件中直到客戶端請(qǐng)求他們。
試驗(yàn)--查找
1 這個(gè)函數(shù)看起更為復(fù)雜,因?yàn)樗{(diào)用我們會(huì)在下一節(jié)討論的三個(gè)管道函數(shù):send_mess_to_server,start_resp_from_server與read_resp_from_server。
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] = ‘\0’;
if (!work_file && (*first_call_ptr == 0)) return(ret_val);
2 下面是搜索的第一個(gè)調(diào)用,在這里*first_call_ptr設(shè)置為true。為了防止我們忘記,立即將其設(shè)置為false。在這個(gè)函數(shù)中創(chuàng)建一個(gè)work_file并且初始化客戶端消息結(jié)構(gòu)。
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 接下是一個(gè)三層的條件測(cè)試。如果消息成功的發(fā)送到服務(wù)器,客戶端會(huì)等待服務(wù)器的響應(yīng)。當(dāng)服務(wù)器的read操作成功,搜索匹配就會(huì)被記入work_file中,而相應(yīng)的entries_matching也會(huì)增加。
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 responding\n”);
}
} else {
fprintf(stderr, “Server not accepting requests\n”);
}
4 下面的測(cè)試檢測(cè)搜索是否成功。然后fseek調(diào)用會(huì)將work_file設(shè)置為數(shù)據(jù)將要寫(xiě)入的下一個(gè)位置。
if (entries_matching == 0) {
fclose(work_file);
work_file = (FILE *)0;
return(ret_val);
}
(void)fseek(work_file, 0L, SEEK_SET);
5 如果這并不是第一次使用特定的搜索模式調(diào)用搜索函數(shù),下面的代碼會(huì)檢測(cè)是否還有余下的匹配。最后,下一個(gè)匹配項(xiàng)會(huì)被讀入ret_val結(jié)構(gòu)中。前面的檢測(cè)認(rèn)為存在一個(gè)匹配項(xiàng)。
} else {
/* not *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);
}
服務(wù)器接口
就如客戶端有一個(gè)對(duì)app_ui.c程序的一個(gè)接口,服務(wù)器端也需要一個(gè)程序來(lái)控制(重命名的)cd_access.c,現(xiàn)在是cd_dbm.c。服務(wù)器的main函數(shù)如下。
試驗(yàn)--server.c
1 我們?cè)诔绦虻拈_(kāi)始處聲明了幾個(gè)全局變量,一個(gè)process_command函數(shù)原型,以及一個(gè)信號(hào)捕獲函數(shù)來(lái)保證一個(gè)干凈的退出。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include “cd_data.h”
#include “cliserv.h”
int save_errno;
static int server_running = 1;
static void process_command(const message_db_t mess_command);
void catch_signals()
{
server_running = 0;
}
2
現(xiàn)在我們來(lái)了解一下main函數(shù)。在檢測(cè)信號(hào)捕獲例程正確之后,程序檢測(cè)我們是否在命令行傳遞了一個(gè)-i選項(xiàng)。如果我們傳遞了,程序就會(huì)創(chuàng)建一個(gè)新的數(shù)據(jù)
庫(kù)。如果cd_dbm.c中的database_initialize例程失敗,就會(huì)顯示一個(gè)錯(cuò)誤消息。如果一切正常而且服務(wù)器正在運(yùn)行,由客戶端來(lái)的請(qǐng)
求就會(huì)被傳遞給process_command函數(shù),這個(gè)函數(shù)我們將會(huì)稍后介紹。
int main(int argc, char *argv[]) {
struct sigaction new_action, old_action;
message_db_t mess_command;
int database_init_type = 0;
new_action.sa_handler = catch_signals;
sigemptyset(&new_action.sa_mask);
new_action.sa_flags = 0;
if ((sigaction(SIGINT, &new_action, &old_action) != 0) ||
(sigaction(SIGHUP, &new_action, &old_action) != 0) ||
(sigaction(SIGTERM, &new_action, &old_action) != 0)) {
fprintf(stderr, “Server startup error, signal catching failed\n”);
exit(EXIT_FAILURE);
}
if (argc > 1) {
argv++;
if (strncmp(“-i”, *argv, 2) == 0) database_init_type = 1;
}
if (!database_initialize(database_init_type)) {
fprintf(stderr, “Server error:-\
could not initialize database\n”);
exit(EXIT_FAILURE);
}
if (!server_starting()) exit(EXIT_FAILURE);
while(server_running) {
if (read_request_from_client(&mess_command)) {
process_command(mess_command);
} else {
if(server_running) fprintf(stderr, “Server ended - can not \
read pipe\n”);
server_running = 0;
}
} /* while */
server_ending();
exit(EXIT_SUCCESS);
}
3 所有的客戶端消息都會(huì)被傳遞給process_command函數(shù),在那里他們會(huì)被傳遞給一個(gè)case語(yǔ)句,從而執(zhí)行cd_dbm.c中的正確調(diào)用。
static void process_command(const message_db_t comm)
{
message_db_t resp;
int first_time = 1;
resp = comm; /* copy command back, then change resp as required */
if (!start_resp_to_client(resp)) {
fprintf(stderr, “Server Warning:-\
start_resp_to_client %d failed\n”, resp.client_pid);
return;
}
resp.response = r_success;
memset(resp.error_text, ‘\0’, sizeof(resp.error_text));
save_errno = 0;
switch(resp.request) {
case s_create_new_database:
if (!database_initialize(1)) resp.response = r_failure;
break;
case s_get_cdc_entry:
resp.cdc_entry_data =
get_cdc_entry(comm.cdc_entry_data.catalog);
break;
case s_get_cdt_entry:
resp.cdt_entry_data =
get_cdt_entry(comm.cdt_entry_data.catalog,
comm.cdt_entry_data.track_no);
break;
case s_add_cdc_entry:
if (!add_cdc_entry(comm.cdc_entry_data)) resp.response =
r_failure;
break;
case s_add_cdt_entry:
if (!add_cdt_entry(comm.cdt_entry_data)) resp.response =
r_failure;
break;
case s_del_cdc_entry:
if (!del_cdc_entry(comm.cdc_entry_data.catalog)) resp.response
= r_failure;
break;
case s_del_cdt_entry:
if (!del_cdt_entry(comm.cdt_entry_data.catalog,
comm.cdt_entry_data.track_no)) resp.response = r_failure;
break;
case s_find_cdc_entry:
do {
resp.cdc_entry_data =
search_cdc_entry(comm.cdc_entry_data.catalog,
&first_time);
if (resp.cdc_entry_data.catalog[0] != 0) {
resp.response = r_success;
if (!send_resp_to_client(resp)) {
fprintf(stderr, “Server Warning:-\
failed to respond to %d\n”, resp.client_pid);
break;
}
} else {
resp.response = r_find_no_more;
}
} while (resp.response == r_success);
break;
default:
resp.response = r_failure;
break;
} /* switch */
sprintf(resp.error_text, “Command failed:\n\t%s\n”,
strerror(save_errno));
if (!send_resp_to_client(resp)) {
fprintf(stderr, “Server Warning:-\
failed to respond to %d\n”, resp.client_pid);
}
end_resp_to_client();
return;
}
在我們了解實(shí)際的管道實(shí)現(xiàn)之前,讓我們來(lái)討論一下在客戶端與服務(wù)器進(jìn)程之間傳遞數(shù)據(jù)需要發(fā)生的事件序列。圖13-9顯示所啟動(dòng)的客戶端與服務(wù)器進(jìn)程以及在處理命令與響應(yīng)時(shí)雙方是如何循環(huán)的。
在這個(gè)實(shí)現(xiàn)中,形勢(shì)有一些困難,因?yàn)閷?duì)于一個(gè)搜索請(qǐng)求,客戶端向服務(wù)器傳遞一個(gè)單一命令,然后希望由服務(wù)器接收一個(gè)或多個(gè)響應(yīng)。這會(huì)導(dǎo)致其他額外的一些復(fù)雜性,主要在客戶端。
本文來(lái)自ChinaUnix博客,如果查看原文請(qǐng)點(diǎn):http://blog.chinaunix.net/u/19185/showart_2024894.html |
|