版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
Oracle·WDPe·WDP分布式文件系統(tǒng)(RPC原理)Oracle高校大數(shù)據(jù)課程系列本課目標(biāo)理解RPC的原理掌握J(rèn)AVA遠(yuǎn)程方法調(diào)用掌握動(dòng)態(tài)代理技術(shù)掌握HadoopRPC原理與應(yīng)用Coursecatalogue課程目錄RPC原理1Java遠(yuǎn)程方法調(diào)用2Java動(dòng)態(tài)代理3Hadoop中的RPC4RPC概述很多分布式系統(tǒng),如瀏覽器和服務(wù)器間的通信,需要在不同的實(shí)體中顯式交換消息,處理諸如消息的編解碼、消息的發(fā)送和接收等非常具體的任務(wù)。如何隱藏底層通信的細(xì)節(jié)是實(shí)現(xiàn)分布式系統(tǒng)訪問(wèn)透明性的重要議題之一。遠(yuǎn)程過(guò)程調(diào)用(RemoteProcedureCall,RPC)由Birrell和Nelson于1984年引入到分布式計(jì)算領(lǐng)域,是解決上述訪問(wèn)透明性的一套精妙方案。隨著RPC的發(fā)展,出現(xiàn)了大量的相關(guān)技術(shù),如XML-RPC、JSON-RPC(JavaScriptObjectNotationRPC),CORBA(CommonObjectRequestBrokerArchitecture,公共對(duì)象請(qǐng)求代理體系結(jié)構(gòu))和RMI(RemoteMethodInvocation,遠(yuǎn)程方法調(diào)用)等。本節(jié)討論的HadoopIPC(Inter-ProcessCommunication,進(jìn)程間通信)屬于RPC的一種比較簡(jiǎn)單的實(shí)現(xiàn)。RPC原理
傳統(tǒng)的過(guò)程調(diào)用中,
主程序?qū)?shù)壓入棧內(nèi)并調(diào)用過(guò)程,
這時(shí)候主程序停止執(zhí)行并開(kāi)始執(zhí)行相應(yīng)的過(guò)程。
被調(diào)用的過(guò)程從棧中獲取參數(shù),
然后執(zhí)行過(guò)程函數(shù):執(zhí)行完畢后,
將返回參數(shù)入?!椿蛘弑4嬖诩拇嫫骼铩?,
并將控制權(quán)交還給調(diào)用方。
調(diào)用方獲取返回參數(shù),
并繼續(xù)執(zhí)行。傳統(tǒng)過(guò)程調(diào)用RPC原理RPC跨越了不同的進(jìn)程(theClient和theServer),其調(diào)用示例如下所示。當(dāng)theClient需要調(diào)用一個(gè)遠(yuǎn)程過(guò)程的時(shí)候,通過(guò)theClient將參數(shù)打包成為一個(gè)消息,并附加被調(diào)用過(guò)程的名字(指明要調(diào)用服務(wù)器上的哪一個(gè)過(guò)程〉,然后發(fā)送消息到服務(wù)器。theClient發(fā)送完消息以后,必須等待服務(wù)器的應(yīng)答,這個(gè)時(shí)候,執(zhí)行流是空閑的。RPC的Server運(yùn)行時(shí)會(huì)阻塞在接收消息的調(diào)用上,當(dāng)接到客戶(hù)端的請(qǐng)求后,它會(huì)解包以獲取請(qǐng)求參數(shù),這類(lèi)似傳統(tǒng)過(guò)程調(diào)用中,被調(diào)用函數(shù)從棧中接收參數(shù),然后確定調(diào)用過(guò)程的名字并調(diào)用相應(yīng)過(guò)程。調(diào)用結(jié)束后,返回值通過(guò)主程序打包并發(fā)送回客戶(hù)端,通知客戶(hù)端調(diào)用結(jié)束。RPC進(jìn)程調(diào)用RPC原理實(shí)現(xiàn)RPC需要關(guān)注下面三個(gè)問(wèn)題:口RPC的語(yǔ)法應(yīng)該與高級(jí)程序設(shè)計(jì)語(yǔ)言中的本地過(guò)程調(diào)用的語(yǔ)法有相同的外觀;口RPC和本地調(diào)用的語(yǔ)義盡可能地類(lèi)似,如參數(shù)傳遞中包含的語(yǔ)義;口RPC的接收者〈也就是服務(wù)器上業(yè)務(wù)代碼的執(zhí)行〉應(yīng)該如同一個(gè)傳統(tǒng)的調(diào)用;RPC原理RPC引人客戶(hù)存根(ClientStub)和服務(wù)器骨架(ServerSkeleton)解決了前面提及的問(wèn)題,可以發(fā)現(xiàn),如果調(diào)用方法的接口確定,那么圖中RPC調(diào)用過(guò)程的很多步驟都可以自動(dòng)生成,生成的這些步驟正是客戶(hù)存根和服務(wù)器骨架的重要組成部分。RPC的實(shí)現(xiàn)一般形式RPC原理-架構(gòu)圖RPC架構(gòu)圖Coursecatalogue課程目錄RPC原理1Java遠(yuǎn)程方法調(diào)用2Java動(dòng)態(tài)代理3Hadoop中的RPC4Java遠(yuǎn)程方法調(diào)用—服務(wù)器端從JavaRMI的開(kāi)發(fā)往往從遠(yuǎn)程接口的定義開(kāi)始,本例使用的遠(yuǎn)程接口如下:RMIQueryStatus接口中的getFileStatus()方法接受一個(gè)字符串參數(shù)filename,返回一個(gè)RMIQueryStatus對(duì)象,這個(gè)方法簡(jiǎn)單地模擬了文件系統(tǒng)中對(duì)文件元信息的查詢(xún)功能。1. importjava.rmi.Remote;2. importjava.rmi.RemoteException;3. //遠(yuǎn)程接口必須聲明為public4. //遠(yuǎn)程接口必須繼承自java.rmi.Remote5. publicinterfaceRMIQueryStatusextendsRemote{6. //遠(yuǎn)程接口中的函數(shù)必須將java.rmi.RemoteException聲明于其throws子句內(nèi)7. RMIFileStatusgetFileStatus(Stringfilename)8. throwsRemoteException;9. }Java遠(yuǎn)程方法調(diào)用—服務(wù)器端RMIQueryStatusImpl繼承自UnicastRemoteObject,并實(shí)現(xiàn)了RMIQueryStatus接口。1. publicclassRMIQueryStatusImpl2. extendsUnicastRemoteObjectimplementsRMIQueryStatus{3. ……4. @Override5. publicRMIFileStatusgetFIleStatus(Stringfilename)throws……{6. RMIFileStatusstatus=newRMIFileStatus(filename);7. ……8. returnstatus;9. }10. }Java遠(yuǎn)程方法調(diào)用—服務(wù)器端啟動(dòng)服務(wù)器FMIQueryStatusServer,該服務(wù)器的main方法創(chuàng)建RMIQueryStatusImpl對(duì)象,并與剛才啟動(dòng)的對(duì)象注冊(cè)點(diǎn)對(duì)話,將遠(yuǎn)端對(duì)象綁定到名字“rmi://:12090/query”上(應(yīng)用這個(gè)例子的時(shí)候,請(qǐng)將這個(gè)URI的主機(jī)部分改為相應(yīng)的主機(jī)名)。雖然main()方法的執(zhí)行很快就結(jié)束了,但服務(wù)器還會(huì)繼續(xù)運(yùn)行,不過(guò),用戶(hù)需要寫(xiě)的服務(wù)器代碼就只有這么多。1. publicstaticvoidmain(String[]args){2. try{3. //創(chuàng)建RMIQueryStatusImpl對(duì)象4. RMIQueryStatusImplqueryService=newRMIQueryStatusImpl();5. LocateRegistry.createRegistry(12090);6. //綁定遠(yuǎn)端對(duì)象到名字7. Naming.rebind(RMI_URL,queryService);8. System.out.println(“Serverready”);9. }catch(Exceptione){10. e.printlnStackTrace();11. }12. }Java遠(yuǎn)程方法調(diào)用—客戶(hù)端
客戶(hù)端對(duì)象在調(diào)用遠(yuǎn)程方法之前,則需要被調(diào)用方法所屬對(duì)象的一個(gè)遠(yuǎn)程引用。客戶(hù)端RMIQueryStatusClient從遠(yuǎn)端對(duì)象注冊(cè)點(diǎn)中,通過(guò)Naming.lookup()獲取遠(yuǎn)程引用。一旦獲取對(duì)象引用,并恢復(fù)了對(duì)象類(lèi)型,客戶(hù)端就可以使用此引用,調(diào)用遠(yuǎn)程對(duì)象的遠(yuǎn)程方法,即getFileStatus()方法。1. try{2. //創(chuàng)建RMIQueryStatusImpl對(duì)象3. RMIQueryStatusquery=4. (RMIQueryStatus)Naming.lookup(RMIQueryStatusServer.RMI_URL);5. //調(diào)用遠(yuǎn)程方法;該調(diào)用如同調(diào)用本地方法6. RMIQueryStatusstatus=query.getFileStatus(“/tmp/testRMI”);7. System.out.println(status);8. }catch(RemoteExceptione){9. //遠(yuǎn)程方法和普通方法的一個(gè)差別:遠(yuǎn)程方法可能拋出RemoteException異常10. e.printStackTrace();11. }Coursecatalogue課程目錄RPC原理1Java遠(yuǎn)程方法調(diào)用2Java動(dòng)態(tài)代理3Hadoop中的RPC4Java動(dòng)態(tài)代理
代理對(duì)象往往實(shí)現(xiàn)和目標(biāo)對(duì)象一致的接口,并作為目標(biāo)對(duì)象的代替,接收對(duì)象用戶(hù)(Client)的調(diào)用,并將全部或部分調(diào)用轉(zhuǎn)發(fā)給目標(biāo)對(duì)象,如下圖所示。在這個(gè)過(guò)程中,實(shí)現(xiàn)代理接口和調(diào)用轉(zhuǎn)發(fā),是代理對(duì)象必須完成的兩個(gè)重要任務(wù),缺一不可。
Java動(dòng)態(tài)代理架構(gòu)Java動(dòng)態(tài)代理通過(guò)Method對(duì)象的invoke()方法,在目標(biāo)對(duì)象target上使用相同的參數(shù)args,調(diào)用了同一個(gè)方法(它們都實(shí)現(xiàn)了同一個(gè)接口),并將結(jié)果返回給調(diào)用者。Java動(dòng)態(tài)代理詳細(xì)過(guò)程Coursecatalogue課程目錄RPC原理1Java遠(yuǎn)程方法調(diào)用2Java動(dòng)態(tài)代理3Hadoop中的RPC4Hadoop中RPCRPC實(shí)際上是分布式計(jì)算中C/S(Client/Server)模型的一個(gè)應(yīng)用實(shí)例,對(duì)于HadoopRPC而言,它具有以下幾個(gè)特點(diǎn)。?透明性。這是所有RPC框架最根本的特點(diǎn),即當(dāng)用戶(hù)在一臺(tái)計(jì)算機(jī)的程序調(diào)用另外一臺(tái)計(jì)算機(jī)上的子程序時(shí),用戶(hù)自身不應(yīng)感覺(jué)到其間涉及跨機(jī)器間的通信,而是感覺(jué)像是在執(zhí)行一個(gè)本地調(diào)用。?高性能。Hadoop各個(gè)系統(tǒng)(如HDFS、YARN、MapReduce等)均采用了Master/Slave結(jié)構(gòu),其中,Master實(shí)際上是一個(gè)RPCServer,它負(fù)責(zé)處理集群中所有Slave發(fā)送的服務(wù)請(qǐng)求,為了保證Master的并發(fā)處理能力,RPCServer應(yīng)是一個(gè)高性能服務(wù)器,能 夠高效地處理來(lái)自多個(gè)Client的并發(fā)RPC請(qǐng)求。?可控性。JDK中已經(jīng)自帶了一個(gè)RPC框架—RMI(RemoteMethodInvocation,遠(yuǎn)程方法調(diào)用),之所以不直接使用該框架,主要是考慮到RPC是Hadoop最底層最核心的模塊之一,保證其輕量級(jí)、高性能和可控性顯得尤為重要,而RMI重量級(jí)過(guò)大且用戶(hù)可控之處太少(如網(wǎng)絡(luò)連接、超時(shí)和緩沖等均難以定制或者修改)。Hadoop中RPC--總體架構(gòu)Hadoop中RPC—使用方法
定義一個(gè)ClientProtocol通信接口,聲明了echo()和add()兩個(gè)方法。需要注意的是,Hadoop中所有自定義RPC接口都需要繼承VersionedProtocol接口,它描述了協(xié)議的版本信息。interfaceClientProtocolextendsorg.apache.hadoop.ipc.VersionedProtocol{//版本號(hào),默認(rèn)情況下,不同版本號(hào)的RPCClient和Server之間不能相互通信publicstaticfinallongversionID=1L;Stringecho(Stringvalue)throwsIOException;intadd(intv1,intv2)throwsIOException;}Hadoop中RPC—使用方法
HadoopRPC協(xié)議通常是一個(gè)Java接口,用戶(hù)需要實(shí)現(xiàn)該接口。對(duì)ClientProtocol接口進(jìn)行簡(jiǎn)單的實(shí)現(xiàn)如下所示publicstaticclassClientProtocolImplimplementsClientProtocol{//重載的方法,用于獲取自定義的協(xié)議版本號(hào),publiclonggetProtocolVersion(Stringprotocol,longclientVersion){returnClientProtocol.versionID;}//重載的方法,用于獲取協(xié)議簽名publicProtocolSignaturegetProtocolSignature(Stringprotocol,longclientVersion,inthashcode){returnnewProtocolSignature(ClientProtocol.versionID,null);}publicStringecho(Stringvalue)throwsIOException{returnvalue;}publicintadd(intv1,intv2)throwsIOException{returnv1+v2;}}Hadoop中RPC—使用方法構(gòu)造并啟動(dòng)RPCServer,直接使用靜態(tài)類(lèi)Builder構(gòu)造一個(gè)RPCServer,并調(diào)用函數(shù)start()啟動(dòng)該ServerServerserver=newRPC.Builder(conf).setProtocol(ClientProtocol.class).setInstance(newClientProtocolImpl()).setBindAddress(ADDRESS).setPort(0).setNumHandlers(5).build();server.start();Hadoop中RPC—使用方法構(gòu)造RPCClient并發(fā)送RPC請(qǐng)求,使用靜態(tài)方法getProxy構(gòu)造客戶(hù)端代理對(duì)象,直接通過(guò)代理對(duì)象調(diào)用遠(yuǎn)程端的方法。經(jīng)過(guò)以上四步,我們便利用HadoopRPC搭建了一個(gè)非常高效的客戶(hù)機(jī)–服務(wù)器網(wǎng)絡(luò)模型。proxy=(ClientProtocol)RPC.getProxy(ClientProtocol.class, ClientProtocol.versionID,addr,conf);intresult=proxy.add(5,6);StringechoResult=proxy.echo("result");Hadoop中RPC—類(lèi)分析(客戶(hù)端)Hadoop中RPC—類(lèi)分析(服務(wù)器端)RPC架構(gòu)圖Coursecatalogue課程目錄RPC原理1Java遠(yuǎn)程方法調(diào)用2Java動(dòng)態(tài)代理3Hadoop中的RPC4ProtocolBufferProtocolBuffers是在Google內(nèi)部廣泛使用的序列化與RPC框架,是幾乎所有Google服務(wù)的黏合劑,2008年Google將ProtocolBuffers開(kāi)源.。一種輕便高效的結(jié)構(gòu)化數(shù)據(jù)存儲(chǔ)格式,可以用于結(jié)構(gòu)化數(shù)據(jù)序列化/反序列化。它很適合做數(shù)據(jù)存儲(chǔ)或RPC的數(shù)據(jù)交換格式,常用作通信協(xié)議、數(shù)據(jù)存儲(chǔ)等領(lǐng)域的與語(yǔ)目無(wú)關(guān)、平臺(tái)無(wú)關(guān)、可擴(kuò)展的序列化結(jié)構(gòu)數(shù)據(jù)格式。ProtocolBuffers官方網(wǎng)站這樣描述它的優(yōu)點(diǎn):□平臺(tái)無(wú)關(guān)、語(yǔ)言無(wú)關(guān);□高性能,解析速度是XML的20~100倍;□體積小,文件大小僅是XML的1/2~1/3;□使用簡(jiǎn)單;□兼容性好。ProtocolBuffer通常編寫(xiě)一個(gè)ProtocolBuffers應(yīng)用需要以下三步:1)定義消息格式文件,通常以proto作為擴(kuò)展名;2)使用Google提供的ProtocolBuffers編譯器生成特定語(yǔ)言(目前支持C++、Java、Python三類(lèi)語(yǔ)言)的代碼文件;3)使用ProtocolBuffers庫(kù)提供的API來(lái)編寫(xiě)應(yīng)用程序。ProtocolBuffer步驟1定義消息格式文件person.proto,該文件描述了通訊錄中某個(gè)人的基本信息,內(nèi)容如下:packagetutorial; //自定義的命名空間optionjava一package="com.example.tutorial"; //生成文件的包名messagePerson{requiredstringname=1;//待描述的結(jié)構(gòu)化數(shù)據(jù)requiredint32id=2;//required表示這個(gè)字段不能為空optionalstringemail=3;//數(shù)字“2”表示字段的數(shù)字別名 //optional表示該字段可以為空messagePhoneNumber{ //內(nèi)部messagerequiredstringnumber=1;optionalint32type=2;repeatedPhoneNumberphone=4;ProtocolBuffer步驟2使用Google提供的ProtocolBuffers編譯器生成Java語(yǔ)言,命令如下:protoc-java_out=.to注意,上面的命令運(yùn)行時(shí)的當(dāng)前路徑是to所在目錄。步驟3使用ProtocolBuffers庫(kù)提供的API編寫(xiě)應(yīng)用程序。該例子創(chuàng)建了一個(gè)Person對(duì)象,先將該對(duì)象保存到文件example.txt中,之后又從文件中讀出并打印出來(lái)。publicclassProtocolBufferExample{staticpublicvoidmain(String[]argv){Personpersonl=Person.newBuilder().setName("DongXicheng").setEmail("").setld(lllll).addPhone(Person.PhoneNumber.newBuilder().setNumber().setType(0)).addPhone(Person.PhoneNumber.newBuilder().setNumber("01025689654").setType(1)).build();try{FileOutputStreamoutput=newFileOutputStream("example.txt");personl.writeTo(output);output.close();}catch(Exceptione){System.out.printIn("WriteError!");FilelnputStreaminput=newFilelnputStream("example.txt");Personperson2=Person.parseFrom(input);System.out.println("person2:"+person2);}catch(Exceptione){System.out.println("ReadError!");ApacheAvroApacheAvro是Hadoop下的一個(gè)子項(xiàng)目。它本身既是一個(gè)序列化框架,同時(shí)也實(shí)現(xiàn)了RPC的功能。Avro官網(wǎng)描述Avro的特性和功能如下:□豐富的數(shù)據(jù)結(jié)構(gòu)類(lèi)型;□快速可壓縮的二進(jìn)制數(shù)據(jù)形式;□存儲(chǔ)持久數(shù)據(jù)的文件容器;□提供遠(yuǎn)程過(guò)程調(diào)用RPC;□簡(jiǎn)單的動(dòng)態(tài)語(yǔ)言結(jié)合功能。ApacheAvro編寫(xiě)一個(gè)Awo應(yīng)用也需如下三步:1)定義消息格式文件,通常以avro作為擴(kuò)展名;2)使用Avro編譯器生成特定語(yǔ)言的代碼文件(可選);3)使用Avro庫(kù)提供的API來(lái)編寫(xiě)應(yīng)用程序。ApacheAvro步驟1定義消息格式文件person.avro,該文件描述了通訊錄中某個(gè)人的基本信息,內(nèi)容如下:{"namespace":"com.example.tutorial","type":"record",’’name":"Person","fields":[{"name”:"name","type":"string"},{"name":"id","type":"int”},{"name":"email”,"type":[’’string","null"]},{"name":"phone","type":{"type":"array","items":{"type":"record","name":"PhoneNumber","fields":[{"name":"number","type":"string"},{"name":’’type","type": ["int","null"]}}}}}}}ApacheAvro步驟2使用Avro編譯器生成Java語(yǔ)言,命令如下: java-jaravro-tools-1.7.4.jarcompileschemaperson.avro.注意,上面的命令運(yùn)行時(shí)的當(dāng)前路徑是person.avro所在目錄。步驟3使用Avro庫(kù)提供的API來(lái)編寫(xiě)應(yīng)用程序。該例子創(chuàng)建一個(gè)Person對(duì)象,先將該對(duì)象保存到文件example.txt中,之后從文件中讀出并打印。publicclassAvroExample{staticpublicvoidmain(String[]argv){PhoneNumberphoneNumberl=PhoneNumber.newBuilder().setNumber().setType(0).build();PhoneNumberphoneNumber2=PhoneNumber.newBuilder().setNumber("01025689654").setType(1
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025版小額貸款抵押合同資產(chǎn)評(píng)估及報(bào)告協(xié)議2篇
- 2025年度個(gè)人與公司租賃房屋修繕責(zé)任合同4篇
- 2025年度個(gè)人旅游規(guī)劃與導(dǎo)游服務(wù)合同2篇
- 2025版室外照明燈具廣告宣傳與品牌推廣合同3篇
- 2025年度煤炭行業(yè)綠色運(yùn)輸體系構(gòu)建合同4篇
- 2025標(biāo)準(zhǔn)新能源材料研發(fā)與采購(gòu)合作協(xié)議3篇
- 2025年度生態(tài)環(huán)保瓷磚批量采購(gòu)合作協(xié)議3篇
- 2025版醫(yī)療健康大數(shù)據(jù)合作開(kāi)發(fā)合同3篇
- 個(gè)性化定制小區(qū)房產(chǎn)買(mǎi)賣(mài)合同(2024版)版B版
- 2025版國(guó)際貿(mào)易糾紛訴訟擔(dān)保委托服務(wù)協(xié)議3篇
- 五年級(jí)上冊(cè)寒假作業(yè)答案(人教版)
- 2025年山東浪潮集團(tuán)限公司招聘25人高頻重點(diǎn)提升(共500題)附帶答案詳解
- 2024年財(cái)政部會(huì)計(jì)法律法規(guī)答題活動(dòng)題目及答案一
- 2025年江西省港口集團(tuán)招聘筆試參考題庫(kù)含答案解析
- (2024年)中國(guó)傳統(tǒng)文化介紹課件
- 液化氣安全檢查及整改方案
- 《冠心病》課件(完整版)
- 2024年云網(wǎng)安全應(yīng)知應(yīng)會(huì)考試題庫(kù)
- 公園保潔服務(wù)投標(biāo)方案
- 光伏電站項(xiàng)目合作開(kāi)發(fā)合同協(xié)議書(shū)三方版
- 2024年秋季新滬教版九年級(jí)上冊(cè)化學(xué)課件 第2章 空氣與水資源第1節(jié) 空氣的組成
評(píng)論
0/150
提交評(píng)論