cd資料庫程式
我們的目標是將程式中處理資料庫的部分與與處理使用者介面的部分分離開來。我們同時希望執行乙個伺服器程序,但是允許多個併發客戶端。我們同時希望在已有的**上進行最小的修改。如果可能,我們保持已有的**不變。
為了使得事情簡單,我們同時希望可以在程式內部建立與刪除管道,所以不需要系統管理員在我們可以使用這些程式之前建立有名管道。
另外保證我們絕不會在一件事情上"忙等待"浪費cpu時間也是很重要的。正如我們所看到的,linux允許我們阻塞,等待事件而不是使用重要的資源。我們應使用管道的阻塞特性來保證我們可以更為有效的使用cpu。總之,在理論上,伺服器應可以為乙個請求的到達等待幾個小時。
實現
1 下面是所需要的#include標頭檔案宣告:
#include
#include
#include
#include
#include
#include
#include
2 然後我們定義有名管道。我們使用乙個管道用於伺服器,另乙個管道用於所有的客戶端。因為也許會有多個客戶端,客戶端在其名字中組合乙個程序id來保證他的管道是唯一的:
#define server_pipe 「/tmp/server_pipe」
#define client_pipe 「/tmp/client_%d_pipe」
#define err_text_len 80
3 我們將命令實現為列舉型別,而不是#define定義。
這是乙個好辦法,允許編譯器進行更多的型別檢測工作,同時有助於程式的除錯,因為許多偵錯程式可以顯示列舉常量的名字,但是不能顯示由#define指令所定義的名字。
第乙個typdef指定了將要傳送給伺服器的請求型別;第二個指定了伺服器向客戶端的響應型別。
typedef enum client_request_e;
typedef enum server_response_e;
4 接下來我們宣告了乙個構成可以在兩個程序之間雙向傳遞的訊息的結構。
typedef struct message_db_t;
5 最後,我們來了解執行資料傳輸的管道介面函式,實現在pipe_imp.c中。這些函式分為伺服器端與客戶端函式,分別在第乙個與第二個塊中:
int server_starting(void);
void server_ending(void);
int read_request_from_client(message_db_t *rec_ptr);
int start_resp_to_client(const message_db_t mess_to_send);
int send_resp_to_client(const message_db_t mess_to_send);
void end_resp_to_client(void);
int client_starting(void);
void client_ending(void);
int send_mess_to_server(message_db_t mess_to_send);
int start_resp_from_server(void);
int read_resp_from_server(message_db_t *rec_ptr);
void end_resp_from_server(void);
我們將討論的其餘部分分為客戶端介面函式與定義在pipe_imp.c中的伺服器端與客戶端函式的詳細討論,而且我們會討論必須的源**。
客戶端介面函式
1 這個檔案實現了在cd_data.h中定義的9個資料庫函式。他通過向伺服器傳遞請求並且由函式中返回伺服器響應來實現操作,類似於乙個中間人。這個檔案由#include與常量定義開始:
#define _posix_source
#include
#include
#include
#include
#include
#include
#include
#include "cd_data.h"
#include "cliserv.h"
2 靜態變數mypid減少了所需要的getpid函式的呼叫次數。我們使用乙個區域性函式,read_one_response,來減少重複的**:
static pid_t mypid;
static int read_one_response(message_db_t *rec_ptr);
3 database_initialize與close例程仍然被呼叫,但是現在分別用來初始化管道介面的客戶端和當客戶端退出時移除多餘的有名管道。
int database_initialize(const int new_database)
/* database_initialize */
void database_close(void)
4 get_cdc_entry例被呼叫用來在指定乙個cd類別標題的情況下由資料中獲取乙個類別實體。在這裡我們將請求編碼進message_db_t結構中,並且將其傳遞給伺服器。然後我們讀取返回的響應放入另乙個不同的message_db_t結構中。如果找到乙個實體,他就會被作為乙個cdc_entry結構被包含進入message_db_t結構中,所以我們需要介紹結構的相關部分:
cdc_entry get_cdc_entry(const char *cd_catalog_ptr)
else
} else
} else
return(ret_val);
}5 下面是我們用來避免重複**的read_one_response函式原始碼:
static int read_one_response(message_db_t *rec_ptr)
end_resp_from_server();
}return(return_code);
}6 其他的get_***,del_***與add_***例程的實現方式與get_cdc_entry函式類似,為了完整,我們在這裡進行介紹。首先是用來讀取cd音軌的函式原始碼:
cdt_entry get_cdt_entry(const char *cd_catalog_ptr, const int track_no)
else
} else
} else
return(ret_val);
}7 下面是兩個是用來新增資料的函式,第乙個向類別中新增,而第二個向音軌資料中新增:
int add_cdc_entry(const cdc_entry entry_to_add)
else
} else
} else
return(0);
}int add_cdt_entry(const cdt_entry entry_to_add)
else
} else
} else
return(0);
}8 最後是兩個用來資料刪除的函式:
int del_cdc_entry(const char *cd_catalog_ptr)
else
} else
} else
return(0);
}int del_cdt_entry(const char *cd_catalog_ptr, const int track_no)
else
} else
} else
return(0);
}
程序間通訊(七)
cd資料庫程式 我們的目標是將程式中處理資料庫的部分與與處理使用者介面的部分分離開來。我們同時希望執行乙個伺服器程序,但是允許多個併發客戶端。我們同時希望在已有的 上進行最小的修改。如果可能,我們保持已有的 不變。為了使得事情簡單,我們同時希望可以在程式內部建立與刪除管道,所以不需要系統管理員在我們...
程序間通訊(七)
cd資料庫程式 我們的目標是將程式中處理資料庫的部分與與處理使用者介面的部分分離開來。我們同時希望執行乙個伺服器程序,但是允許多個併發客戶端。我們同時希望在已有的 上進行最小的修改。如果可能,我們保持已有的 不變。為了使得事情簡單,我們同時希望可以在程式內部建立與刪除管道,所以不需要系統管理員在我們...
程序間通訊(七)
cd資料庫程式 我們的目標是將程式中處理資料庫的部分與與處理使用者介面的部分分離開來。我們同時希望執行乙個伺服器程序,但是允許多個併發客戶端。我們同時希望在已有的 上進行最小的修改。如果可能,我們保持已有的 不變。為了使得事情簡單,我們同時希望可以在程式內部建立與刪除管道,所以不需要系統管理員在我們...