




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、分布式系統(tǒng)的重要不言而喻, 下面是使用rpcgen工具構(gòu)建一個(gè)分布式程序的例子, 其實(shí)主要就是<TCP/IP進(jìn)行網(wǎng)際互聯(lián)>卷3上面的那個(gè)例子, 就是下面這本書. 另外還參考了<分布式系統(tǒng) 原理與范例>這本書, 即Andrew S. Tanenbaum寫的這本, 這本書是學(xué)習(xí)分布式的必讀書之一. 相當(dāng)不錯(cuò). 整個(gè)文章分為三部分, 第一部分是對(duì)RPC(遠(yuǎn)程過程調(diào)用)的一個(gè)介紹, 第二部分是對(duì)使用rpcgen構(gòu)建分布式程序的一個(gè)介紹, 第三部分是使用rpcgen構(gòu)建分布式程序的詳細(xì)步驟.可以先按照第三部分的步驟自己先試試, 如果有興趣再回過頭來看它的介紹.另外, 我寫的這個(gè)只
2、是一個(gè)入門, 如果以后有機(jī)會(huì)再詳細(xì)地討論一下內(nèi)部的機(jī)理. 事情總是一步一步來的. 一. RPC概念1.1 介紹 在中間件的實(shí)現(xiàn)中,引入了遠(yuǎn)程過程調(diào)用RPC(Remote Procedure Call)的概念。同時(shí),許多分布式系統(tǒng)是基于進(jìn)程間的顯式消息交換的,然而消息的發(fā)送和接收過程無法隱藏通信的存在,而通信的隱藏對(duì)于在分布式系統(tǒng)中實(shí) 現(xiàn)訪問透明性是極為重要的。因此這個(gè)問題在很長一段時(shí)間內(nèi)都沒有找到合適的解決辦法,后來Birrel和Nelson在1984年的一篇論文中引入了一套 與傳統(tǒng)方法截然不同的通信處理手段。他們認(rèn)為應(yīng)該允許程序調(diào)用位于其它機(jī)器上的進(jìn)程。當(dāng)機(jī)器A上的進(jìn)程調(diào)用B上的進(jìn)程時(shí),A上
3、的調(diào)用進(jìn)程被掛起,而B上的 被調(diào)用進(jìn)程開始執(zhí)行。調(diào)用方可以通過使用參數(shù)將信息傳送給被調(diào)用方,然后可以通過傳回的結(jié)果得到信息。編程人員看不到任何消息傳遞過程。這種方法就稱為遠(yuǎn) 程過程調(diào)用RPC。目前,RPC作為一種廣泛使用的技術(shù),已成為許多分布式系統(tǒng)的基礎(chǔ)。1.2 構(gòu)建分布式程序的兩種模式在設(shè)計(jì)分布式應(yīng)用時(shí),程序員可以使用下列兩種方法之一:面向通信的設(shè)計(jì) 由通信協(xié)議開始。設(shè)計(jì)報(bào)文格式和語法,指明對(duì)每個(gè)傳入報(bào)文將如何反應(yīng)以及如何產(chǎn)生每個(gè)外發(fā)報(bào)文,以此來設(shè)計(jì)客戶和服務(wù)器各構(gòu)件。面向應(yīng)用的設(shè)計(jì) 由應(yīng)用開始。設(shè)計(jì)常規(guī)的應(yīng)用程序來解決問題。構(gòu)建并測試可在單臺(tái)機(jī)器上運(yùn)行的常規(guī)程序的工作版本。將這個(gè)程序劃分成
4、兩個(gè)或多個(gè)程序片,加入通信協(xié)議以允許每片程序在單獨(dú)的計(jì)算機(jī)上執(zhí)行。 遠(yuǎn)程過程調(diào)用模型使用面向應(yīng)用的方法,它強(qiáng)調(diào)的是所要解決的問題而不是所需要的通信。利用遠(yuǎn)程過程調(diào)用,程序員首先設(shè)計(jì)一個(gè)解決問題的常規(guī)程序,接著將其 劃分成若趕干片,這些程序片運(yùn)行在兩臺(tái)或更多的計(jì)算機(jī)上。程序員可遵循良好的設(shè)計(jì)原則,以便使代碼模塊化并且可維護(hù)。 在理想的情況下,遠(yuǎn)程過程調(diào)用提供的不只是抽象上的概念。它允許程序員在將一個(gè)程序劃分成若干片之前,先構(gòu)建,編譯和測試一個(gè)解決該問題的常規(guī)程序的版 本,以便確保能夠正確解決問題。不但如此,因?yàn)镽PC以方法調(diào)用為邊界劃分程序,所以將程序劃分為本地部分和遠(yuǎn)程部分并不會(huì)引起程序結(jié)構(gòu)的
5、很大變化。實(shí)際 上,將某些過程從一個(gè)程序轉(zhuǎn)移到遠(yuǎn)程機(jī)器上時(shí),有可能不需要改變。1.3 常規(guī)過程調(diào)用的概念性模型 如下圖所示,為常規(guī)的程序調(diào)用。本地過程調(diào)用.jpg1.4 遠(yuǎn)程過程調(diào)用模型 遠(yuǎn)程過程調(diào)用模型使用了和常規(guī)程序一樣的過程抽象,但是它允許一個(gè)過程的邊界跨越兩臺(tái)計(jì)算機(jī)。如下圖所示。遠(yuǎn)程過程調(diào)用.jpg1.5 常規(guī)過程調(diào)用的執(zhí)行和返回 程序從一個(gè)主程序開始執(zhí)行,并一直繼續(xù)下去,直到遇到一個(gè)過程調(diào)用。這個(gè)調(diào)用使程序的執(zhí)行轉(zhuǎn)入到某個(gè)指定的代碼處繼續(xù)執(zhí)行。常規(guī)過程調(diào)用的執(zhí)行流程如下圖所示:常規(guī)過程調(diào)用.jpg1.6 分布式系統(tǒng)的過程模型 在分布式系統(tǒng)中,其中的某個(gè)過程有可能在另外的機(jī)器上,因此,
6、其調(diào)用過程模型如下圖如示:分布式中的過程調(diào)用.jpg1.7 客戶-服務(wù)器和RPC之間的對(duì)比 遠(yuǎn)程過程調(diào)用允許程序員以一種他所熟悉的環(huán)境來思考客戶和服務(wù)器的交互,如同常規(guī)的過程調(diào)用,遠(yuǎn)程過程調(diào)用把控制權(quán)傳遞給被調(diào)用的進(jìn)程。也像常規(guī)過程調(diào)用一樣,在調(diào)用進(jìn)程中,系統(tǒng)把調(diào)用過程的執(zhí)行掛起。而只允許被調(diào)用過程執(zhí)行。 當(dāng)遠(yuǎn)程程序發(fā)出響應(yīng)時(shí),這對(duì)應(yīng)于在常規(guī)過程調(diào)用中執(zhí)行return??刂茩?quán)返回給調(diào)用者,被調(diào)用過程停止執(zhí)行。嵌套的過程調(diào)用的想法也可應(yīng)用到遠(yuǎn)程過程調(diào)用。遠(yuǎn)程過程調(diào)用也許要調(diào)用另一個(gè)遠(yuǎn)程過程。如上圖所示。二. 分布式程序的生成原理 RPC的實(shí)現(xiàn)包括一個(gè)工具,它自動(dòng)地生成實(shí)現(xiàn)分布式程序所需要的大多數(shù)
7、代碼。這個(gè)工具叫做rpcgen,它讀取一個(gè)規(guī)約文件作為輸入,生成C的源文件作為 輸出。規(guī)范文件包含常量,全局?jǐn)?shù)據(jù)類型,全局?jǐn)?shù)據(jù)以及遠(yuǎn)程過程(包括過程參數(shù)和結(jié)果類型)的聲明。rpcgen產(chǎn)生的代碼包含了實(shí)現(xiàn)客戶和服務(wù)器程序所需 要的大部分源代碼。具體地說,rpcgen包括參數(shù)整理,發(fā)送RPC報(bào)文,把傳入調(diào)用分派到正確的過程,發(fā)送應(yīng)答,在參數(shù)和結(jié)構(gòu)的外部表示和本地?cái)?shù)據(jù)表示 之間進(jìn)行轉(zhuǎn)換。rpcgen的輸出與應(yīng)用程序和程序員編寫的少數(shù)文件相結(jié)合后,便產(chǎn)生出了完整的客戶和服務(wù)器程序。 rpcgen讀取輸入文件,該文件包含有對(duì)遠(yuǎn)程過程的說明。它產(chǎn)生四個(gè)輸出文件,每個(gè)文件都包含有源代碼,如果輸入的文件(即
8、規(guī)約文件)具有名字q.x, 則輸出的文件如下所示:q.h:常量和類型的聲明q_xdr.c XDR過程調(diào)用q_clnt.c 客戶端的通信接口q_svc.c 服務(wù)器端的通信接口具體步驟在第三部分。三. 分布式程序的生成步驟 在這里,舉的例子就是Douglas E.Comer書上的那個(gè)例子。這個(gè)例子重點(diǎn)在于解釋rpcgen 如何工作的。3.1 查找字典 在該例子中,考慮實(shí)現(xiàn)一個(gè)簡單的數(shù)據(jù)庫功能的程序。該數(shù)據(jù)庫提供四個(gè)基本的操作:初始化,插入一個(gè)新的條目,刪除一個(gè)條目,查找一個(gè)條目。假設(shè)每個(gè)條目都 是一個(gè)單詞。因此該數(shù)據(jù)庫的功能就可以看作是一個(gè)字典。應(yīng)用程序插入一組單詞,接著使用數(shù)據(jù)庫來檢查新單詞,以
9、便知道這個(gè)單詞是否在該字典中。3.2 構(gòu)建程序的八個(gè)步驟(1)構(gòu)建解決該問題的常規(guī)應(yīng)用程序 要構(gòu)建這個(gè)字典應(yīng)用例子的分布式版本,第一步要求程序員構(gòu)造解決該問題的常規(guī)程序。文件dict.c包含了該常規(guī)程序:CODE:/* dict.c */#include<stdio.h>#include<stdlib.h>#include<ctype.h>#include<string.h>#define MAXWORD 50 /* 每個(gè)單詞的長度限制*/#define DICTSIZ 100 /* 字典一共可以
10、存放多少個(gè)單詞 */char dictDICTSIZMAXWORD+1;int nwords = 0;/* * nextin(): 讀入命令與單詞 */int nextin(char *cmd, char *word) int i, j; char buf100 = 0; if (fgets(buf, sizeof(buf)-1, stdin) = NULL) return -1; for (i = 0; i < 100; i+) if (bufi != ' ') break; if (i = 100) return -1; *
11、cmd = bufi; while (1) if (i = 100) return -1; i+; if (bufi = ' ') continue; else if (bufi = 'n') return 0; else break; j = 0; while (bufi != 'n') *word+ = bufi; i+; j+; return j;/* * initw(): 初始化這個(gè)字典 */int initw() nwords = 0; return 1;/* * ins
12、ertw(const char *word): 向這個(gè)字典中加入單詞 */int insertw(const char *word) strcpy(dictnwords, word); nwords+; return nwords;/* * deletew(const char *word): 從這個(gè)字典中刪除單詞 */int deletew(const char *word) int i; for (i = 0; i < nwords; i+) if (strcmp(word, dicti) = 0) nwords-;
13、strcpy(dicti, dictnwords); return 1; return 0;/* * lookupw(const char *word): 在字典中查找某個(gè)單詞 */int lookupw(const char *word) int i; for (i = 0; i < nwords; i+) if (strcmp(word, dicti) = 0) return 1; return 0;int main(int argc, char *argv) char wordMAXWORD+1; char cmd; int wrdlen
14、; while (1) wrdlen = nextin(&cmd, word); if (wrdlen < 0) exit(0); wordwrdlen = '0' switch(cmd) case 'I': initw(); printf("Dictionary initialized to empty.n"); break; case 'i': insertw(word); printf("%s inserted.n", word); break; case 'd': if
15、 (deletew(word) printf("%s deleted.n", word); else printf("%s not found.n", word); break; case 'l': if (lookupw(word) printf("%s is found.n", word); else printf("%s is not found.n", word); break; case 'q': printf("program quits.n"); e
16、xit(0); default: printf("command %c invalid.n", cmd); break; return 0;該dict.c程序使用了一個(gè)二維數(shù)組來存儲(chǔ)單詞。全局變量nwords記錄了任何時(shí)刻字典中單詞的數(shù)量。主程序包含一個(gè)循環(huán),在每次循環(huán)中讀取并處理輸入文件中的一行。 該程序就是普通的常規(guī)程序,編譯并運(yùn)行: gcc dict.c o dict ./dict 可以如下來實(shí)驗(yàn)QUOTE: I i hello i world l hello d hello l hello q(2)將程序劃分成兩部分 常規(guī)程序一旦構(gòu)建完成并經(jīng)過測試,就可以將它劃分成
17、本地構(gòu)件和遠(yuǎn)程構(gòu)件了。下圖為這個(gè)程序的過程調(diào)用情況:程序組織情況.jpg在考慮哪個(gè)過程可以轉(zhuǎn)移到遠(yuǎn)程機(jī)器上時(shí),程序員必須考慮每個(gè)過程所需要的資源。例如nextin在每次被調(diào)用時(shí)要讀取下一個(gè)輸入行,并對(duì)它進(jìn)行分析。因?yàn)?它需要訪問程序的標(biāo)準(zhǔn)輸入,所以nextin必須放在主程序的機(jī)器中。簡單來說就是執(zhí)行I/O或者訪問文件描述符的過程不能輕易地轉(zhuǎn)移到遠(yuǎn)程機(jī)器中。 同時(shí)還要考慮每個(gè)過程所要訪問的數(shù)據(jù)所處的位置。例如,lookupw需要訪問全部單詞數(shù)據(jù)庫,如果執(zhí)行l(wèi)ookupw的機(jī)器不同于字典所處的機(jī)器,對(duì) lookupw的RPC調(diào)用就必須將整個(gè)字典作為參數(shù)來傳遞。將巨大的數(shù)據(jù)結(jié)構(gòu)作為參數(shù)傳遞給遠(yuǎn)程過程
18、的效率非常低。一般來說執(zhí)行過程的機(jī)器應(yīng)當(dāng)與放置過 程所要訪問數(shù)據(jù)的機(jī)器是同一臺(tái),將巨大的數(shù)據(jù)結(jié)構(gòu)傳遞給遠(yuǎn)程過程的效率是很低的。 對(duì)于本應(yīng)用來說,應(yīng)當(dāng)把過程insertw,deletew,initw,lookupw和字典本身放在同一臺(tái)機(jī)器中。下圖說明了這種劃分方式:劃分程序.jpg相當(dāng)于將dict.c 劃分成了兩個(gè)文件dict1.c和dict2.c。這里的兩個(gè)程序只是一個(gè)示例,不需要寫出來,但是后面將要編寫與這兩個(gè)程序相似的另外兩個(gè)程序。 文件dict1.c包含主程序和過程nextin:CODE:/* dict1.c */#include<stdio.h>#include<st
19、dlib.h>#include<ctype.h>#include<string.h>#define MAXWORD 50char dictDICTSIZMAXWORD+1;int nwords = 0;int nextin(char *cmd, char *word) int i, j; char buf100 = 0; if (fgets(buf, sizeof(buf)-1, stdin) = NULL) return -1; for (i = 0; i < 100; i+) if (bufi != ' ') break; if (i =
20、 100) return -1; *cmd = bufi; while (1) if (i = 100) return -1; i+; if (bufi = ' ') continue; else if (bufi = 'n') return 0; else break; j = 0; while (bufi != 'n') *word+ = bufi; i+; j+; return j;int main(int argc, char *argv) char wordMAXWORD+1; char cmd; int wrdlen; while (
21、1) wrdlen = nextin(&cmd, word); if (wrdlen < 0) exit(0); wordwrdlen = '0' switch(cmd) case 'I': initw(); printf("Dictionary initialized to empty.n"); break; case 'i': insertw(word); printf("%s inserted.n", word); break; case 'd': if (deletew
22、(word) printf("%s deleted.n", word); else printf("%s not found.n", word); break; case 'l': if (lookupw(word) printf("%s is found.n", word); else printf("%s is not found.n", word); break; case 'q': printf("program quits.n"); exit(0); d
23、efault: printf("command %c invalid.n", cmd); break; return 0;文件dict2.c包含了來自最初的應(yīng)用程序的一些函數(shù)。它們將成為遠(yuǎn)程程序的一部分。另外,還包含對(duì)各個(gè)函數(shù)要共享的全局?jǐn)?shù)據(jù)的聲明。CODE:/* dict2.c */#include<string.h>#define MAXWORD 50#define DICTSIZ 100char dictDICTSIZMAXWORD+1;int nwords = 0;int initw() nwords = 0; return 1;int insertw(
24、char *word) strcpy(dictnwords, word); nwords+; return nwords;int deletew(char *word) int i; for (i = 0; i < nwords; i+) if (strcmp(word, dicti) = 0) nwords-; strcpy(dicti, dictnwords); return 1; return 0;int lookupw(char *word) int i; for (i = 0; i < nwords; i+) if (strcmp(word, dicti) = 0) re
25、turn 1; return 0;注意,對(duì)符號(hào)常量MAXWORD的定義在兩個(gè)構(gòu)件中都出現(xiàn)了,因?yàn)樗鼈兌家暶饔糜诖鎯?chǔ)字的變量,然而,只有在文件dict2.c中才含有用于存儲(chǔ)字典的數(shù)據(jù)結(jié)構(gòu)的聲明,因?yàn)橹挥羞h(yuǎn)程過程才包含字典的數(shù)據(jù)結(jié)構(gòu)。 此時(shí) gcc c dict1.c gcc c dict2.c 編譯一下檢查是否有語法錯(cuò)誤。(3)創(chuàng)建rpcgen規(guī)約 程序員一旦為某個(gè)分布式程序選擇了一種結(jié)構(gòu),就可以準(zhǔn)備rpc規(guī)約了。從本質(zhì)上說,rpcgen規(guī)約文件包含了對(duì)遠(yuǎn)程程序的聲明以及它所使用的數(shù)據(jù)結(jié)構(gòu)。 該規(guī)約文件包含常量,類型定義,以及對(duì)客戶和服務(wù)器程序的聲明。即: 聲明在客戶或服務(wù)器中所使用的常量 聲
26、明所使用的數(shù)據(jù)類型 聲明遠(yuǎn)程程序,每個(gè)程序中所包含的過程以及它們的參數(shù)類型 所有這些聲明必須用RPC編程語言來給出。對(duì)于該例子的規(guī)約如下,rdict.x:CODE:/* rdict.x */const MAXWORD = 50;const DICTSIZ = 100;struct example int exfield1; char exfield2;program RDICTPROG /* 遠(yuǎn)程程序的名稱 */ version RDICTVERS /* 版本 */ int INITW(void) = 1; /* 第一個(gè)函數(shù) */ int
27、INSERTW(string) = 2; /* 第二個(gè)函數(shù) */ int DELETEW(string) = 3; /* 第三個(gè)函數(shù) */ int LOOKUPW(string)= 4; /* 第四個(gè)函數(shù) */ = 1; /* 該程序的版本號(hào) */ = 0x30090949; /* 遠(yuǎn)程程序標(biāo)識(shí), 必須唯一 */(4)運(yùn)行rpcgen 在完成了規(guī)約后,程序員運(yùn)行rpcgen來檢查語法錯(cuò)誤,并且生成四個(gè)代碼文件:rdict.h rdic
28、t_clnt.c rdict_svc.c和rdict_xdr.c。 輸入命令:rpcgen rdict.x rdict.h為rpcgen產(chǎn)生的.h文件,即頭文件。 rdict_xdr.c為rpcgen產(chǎn)生的XDR轉(zhuǎn)換文件,XDR即External Data Representation。是數(shù)據(jù)傳輸?shù)囊粋€(gè)規(guī)范。 rdict_clnt.c為rpcgen產(chǎn)生的客戶端的代碼。 rdict_svc.c為rpcgen產(chǎn)生的服務(wù)器端的代碼。 這些文件一旦生成,就可以被編譯成目標(biāo)代碼的形式。 gcc c rdict_clnt.c gcc c rdict_svc.c gcc c rdict_xdr.c 到了這一
29、步,需要程序員再編寫接口過程。程序員需要編寫四個(gè)程序,分別為客戶端程序與客戶端的接口程序,服務(wù)器程序與服務(wù)器端的接口程序。如下圖所示,圖中陰影部分為需要程序員自己編寫的代碼:程序框架.jpg(5)編寫接口過程 rpcgen產(chǎn)生的文件并沒有構(gòu)成完整的程序,它還要求程序員必須編寫客戶端和服務(wù)器端的接口。 客戶端接口rdict_cif.c程序如下所示:CODE:/* rdict_cif.c */#include<rpc/rpc.h>#include<stdio.h>#define RPC_CLNT#include"rdict.h"extern CLIENT
30、 *handle;static int *ret;int initw() ret = initw_1(0, handle); return ret = NULL ? 0 : *ret;int insertw(char *word) char *arg; arg = &word; ret = insertw_1(arg, handle); return ret = NULL ? 0 : *ret;int deletew(char *word) char *arg; arg = &word; ret = deletew_1(arg, handle); return ret = NU
31、LL ? 0 : *ret;int lookupw(char *word) char *arg; arg = &word; ret = lookupw_1(arg, handle); return ret = NULL ? 0 : *ret;服務(wù)器端接口例程rdict_sif.c如下:CODE:/* rdict_sif.c */#include<rpc/rpc.h>#define RPC_SVC#include"rdict.h"static int retcode;int initw(void), insertw(char *), deletew(cha
32、r *), lookupw(char *);int *insertw_1_svc(char *w, struct svc_req* rqstp) retcode = insertw(*(char*)w); return &retcode;int *initw_1_svc(void* w, struct svc_req* rqstp) retcode = initw(); return &retcode;int *deletew_1_svc(char *w, struct svc_req* rqstp) retcode = deletew(*(char*)w); return &
33、amp;retcode;int *lookupw_1_svc(char *w, struct svc_req *rqstp) retcode = lookupw(*(char*)w); return &retcode;(6)編譯和鏈接客戶程序 首先 gcc c rdict_cif.c編譯客戶端的接口程序。 再gcc c rdict_xdr.c編譯XDR程序。 而客戶端程序還需要聲明并初始化一個(gè)句柄,RPC通信例程用該句柄和服務(wù)器通信。 客戶端程序rdict.c如下:CODE:/* rdict.c */#include<rpc/rpc.h>#include<stdlib
34、.h>#include<stdio.h>#include<ctype.h>#include"rdict.h"#define MAXWORD 50#define RMACHINE "" /* 服務(wù)器端ip address */CLIENT *handle;int nextin(char *cmd, char *word) int i, j; char buf100 = 0; if (fgets(buf, sizeof(buf)-1, stdin) = NULL) return -1;
35、for (i = 0; i < 100; i+) if (bufi != ' ') break; if (i = 100) return -1; *cmd = bufi; while (1) if (i = 100) return -1; i+; if (bufi = ' ') continue; else if (bufi = 'n') return 0; else break; j = 0; while (bufi != 'n') *word+ = bufi; i+; j+; return j;int main(int
36、argc, char *argv) char wordMAXWORD+1; char cmd; int wrdlen; handle = clnt_create(RMACHINE, RDICTPROG, RDICTVERS, "tcp"); if (handle = NULL) printf("cound not contact remote program.n"); exit(1); while (1) wrdlen = nextin(&cmd, word); if (wrdlen < 0) exit(0); wordwrdlen = '0' switch(cmd) case 'I': initw(); printf("Dictionary initialized to empty.n"); break; case 'i': insertw(word); printf("%s inserted.n", word); break; case 'd': if (deletew(word) printf("%s deleted.n", word); els
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 網(wǎng)絡(luò)管理員應(yīng)用技巧試題及答案揭秘
- 計(jì)算機(jī)二級(jí)MySQL考試模擬題及答案
- 財(cái)務(wù)決策邏輯模型的分析試題及答案
- 2025年MySQL數(shù)據(jù)優(yōu)化試題及答案
- 全景分析計(jì)算機(jī)二級(jí)Python試題及答案
- 法律投行面試題及答案大全
- Python云服務(wù)集成考題及答案
- 計(jì)算機(jī)基礎(chǔ)知識(shí)直通車試題及答案
- MySQL并發(fā)控制的試題及答案
- 法律考試題及答案解析
- 郵政寄遞安全培訓(xùn)
- 狂犬病知識(shí)教學(xué)課件
- 血透室手衛(wèi)生規(guī)范
- 儲(chǔ)能測試面試題及答案
- 銷售公司內(nèi)勤員工績效考核制度
- 社工招聘筆試題庫及答案
- 2025年-山東省建筑安全員A證考試題庫附答案
- 電子商務(wù)教學(xué)技術(shù)應(yīng)用試題及答案
- 陜西省歷年中考作文題(2002-2024)
- 《全消光錦綸6切片制備工藝流程分析9200字(論文)》
- 收費(fèi)室考核細(xì)則
評(píng)論
0/150
提交評(píng)論