付費(fèi)下載
下載本文檔
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第14章進(jìn)間通問題,它的實(shí)際意義在于怎么樣讓多個(gè)進(jìn)可以互相的數(shù)據(jù)。在Linux/UNIX環(huán)境下進(jìn)一個(gè)大型的應(yīng)用系統(tǒng),往往需要眾多進(jìn)協(xié)作,間通信的重要性顯而易見。了Linux環(huán)境下的幾主要進(jìn)通信并針對(duì)每個(gè)通的鍵技術(shù)環(huán)給出詳細(xì)實(shí)例。為達(dá)到闡明問題的目的,本章還對(duì)某些通信的內(nèi)部實(shí)現(xiàn)機(jī)制進(jìn)行了分析。進(jìn)間通信簡(jiǎn)在早期,UNIX系統(tǒng)IPC就是進(jìn)間通信方式的統(tǒng)稱,進(jìn)間通信就是可以讓多個(gè)進(jìn)可以互相之間。這種包括序運(yùn)行的適時(shí)數(shù)據(jù),也包括對(duì)方的代碼段,這是在實(shí)際應(yīng)用中及其常見的問題,進(jìn)間通信示意圖如圖14-1所示。圖14-1進(jìn)間通信簡(jiǎn)上圖所示進(jìn)間通信的模式,進(jìn) 和進(jìn) 在運(yùn)行的過中會(huì)需要一些外部的數(shù)據(jù)進(jìn)間通信的難進(jìn)運(yùn)行期間,其地址空間對(duì)于其他進(jìn)是不可見的(這只是傳統(tǒng)上的進(jìn)概念,在IPC內(nèi)存共享機(jī)制打破了這個(gè)概念),在系統(tǒng)中它們是相對(duì)獨(dú)立的,并不能互相對(duì)方,如圖14-2所示。圖14-2進(jìn)在內(nèi)存中的地Linux/UNIX系統(tǒng)提供一種中間轉(zhuǎn)發(fā)的機(jī)制,為多個(gè)進(jìn)建立起互相通信的數(shù)據(jù)通道。在上述問題中,當(dāng)進(jìn)A與進(jìn)B通信時(shí),通過中間的IPC方式來轉(zhuǎn)發(fā)數(shù)據(jù)到目標(biāo)進(jìn)。IPC的多種方單的使用文件系統(tǒng)實(shí)現(xiàn)多進(jìn)共享文件數(shù)據(jù)、以及父共享數(shù)據(jù)段,到高級(jí)應(yīng)用的管14-1IPC類IPC類FIFO(FirstInSystemVIPC/POSIX消息隊(duì)SOCKET注意:其余的技術(shù)中,在不同的系統(tǒng)中會(huì)有不同的限制,以及不同的特點(diǎn)。本書只描述 管道的概管道是Linux/UNIX系統(tǒng)中比較原始的進(jìn)間通信形式,它實(shí)現(xiàn)數(shù)據(jù)以一種數(shù)據(jù)流的道。它只是進(jìn)的一種資源,會(huì)隨著進(jìn)的結(jié)束而被系統(tǒng)清除。管道通信是在UNIX系統(tǒng)中應(yīng)用比較頻繁的式,例如使用grep查找。#ls|grep 上述命令中使用的是半雙工管道,即grep命令的輸入是ls命令的輸出。管道從數(shù)據(jù)流半雙工管盡管有如此限制,半雙工管道還是最常用的通信方式。Linuxpipe函數(shù)創(chuàng)建一個(gè)半雙工管道,其函數(shù)原型如下:#include#includeintpipe(intfd[2])intfd[2]2的文件描述符數(shù)組,fd[0]是讀出端,fd[1]是寫入端,函數(shù)的返回值為0表示成功,–1表示失敗。當(dāng)函數(shù)成功返回,則自動(dòng)了一個(gè)從fd[1]到下面實(shí)例演示了如何使用pipe函數(shù)創(chuàng)建管道以及關(guān)閉管道。序中先使用函數(shù)pipe#include<stdio.h>intmain(void{intchar/*if((pipe(fd))<0}write(fd[1],"createthepipesuccessfully!\n",31read(fd[0],str,sizeof(str));/*從管道讀出端讀出數(shù)據(jù)*/printf("%s",str);printf("pipefiledescriptorsare%d,%d\n",fd[0],fd[1])closeclose/*關(guān)閉管道的讀入文件描述符/*關(guān)閉管道的讀出文件描述符return} 14-1opro_pipe.c管道的打開以及關(guān)閉操$gccopro_pipe.c–o $./$./createthepipesuccessfullypipefiledescriptorsare 注意:fd并沒有和任何有名文件相關(guān)聯(lián),之后向管道一端寫入數(shù)據(jù)并從讀出端讀出數(shù)據(jù),將數(shù)據(jù)輸出到標(biāo)準(zhǔn)輸出。在序的最后使用close函數(shù)關(guān)閉半雙工管道的讀寫操readwrite函數(shù)對(duì)管道進(jìn)行操作。當(dāng)對(duì)一個(gè)讀端已經(jīng)關(guān)閉的管道進(jìn)行寫操作時(shí),會(huì)產(chǎn)生信號(hào)SIGPIPE,說明管道讀端已經(jīng)關(guān)閉,并且write操作返回為–1,errno的值為EPIPE,對(duì)于SIGPIPE信號(hào)可以進(jìn)行捕捉處理。如果寫入進(jìn)不能捕捉或者干脆忽略SIGPIPE信號(hào),則寫入進(jìn)會(huì)中斷。如果要建立一個(gè)父進(jìn)到的數(shù)據(jù)通道,可以先調(diào)用pipe函數(shù)緊接著調(diào)用fork函數(shù),由于自動(dòng)繼承父進(jìn)的數(shù)據(jù)段,則父同時(shí)擁有管道的操作權(quán),此時(shí)管道的方向取決于用戶怎么該管道,管道示意圖如圖14-3所示。14-3管道示意當(dāng)用戶想要一個(gè)父進(jìn)到的數(shù)據(jù)通道時(shí),可以在父進(jìn)中關(guān)閉管道的讀出端,相應(yīng)的在中關(guān)閉管道的輸出端,如圖14-3B所示。相反的,當(dāng)?shù)礁高M(jìn)的數(shù)據(jù)通道時(shí),在父進(jìn)中關(guān)閉輸出,中關(guān)閉讀入即可??傊?,使用pipe及fork組合,可以構(gòu)造出所有的父進(jìn)與,或到兄弟進(jìn)的管道。下面實(shí)例演示了使用pipe以及fork組合實(shí)現(xiàn)父通信。序中先使用pipe函數(shù)建立管道,使用fork函數(shù)創(chuàng)建。在父中管道的數(shù)據(jù)方向,并在父進(jìn)中#include<unistd.h>#include<stdio.h>#include<fcntl.h>#include<unistd.h>#include<stdio.h>#include<fcntl.h>#defineBUFESPIPE_BUF*PIPE_BUF管道默intmain(void{intpid_tpid;intif((pipe(fd))<0perror("failedtopipe");exit(1);}if((pid=fork())0){perror("failedtofork");exit(1);}elseif(pid>0){close/*/*父write(fd[1],exit(omyson!\n14*}elseclose(fd[1]); len=read(fd[0],buf,BUFS if(len<0perror("processfailedwhenreadapipe");exit(1);}write(STDOUT_FILENObuf }}序14-2fath_chil.c$gccfath_chil.c–o $./$./omy序中使用pipe函數(shù)加fork組合,實(shí)現(xiàn)父進(jìn)到的通信。序在父進(jìn)段中關(guān)注意:這里的問題是管道的順序,當(dāng)父進(jìn)創(chuàng)建了管道,只有已經(jīng)繼承了管道后,父進(jìn)才可以執(zhí)行關(guān)閉管道的操作。如果在fork之前已經(jīng)關(guān)閉管道,2個(gè)。在1個(gè)中發(fā)送消2個(gè),第2個(gè)中讀出消在vi編輯器中編輯該序#include<unistd.h>#include<stdio.h>#include<stdlib.h>#include<fcntl.h>#include#defineBUFESvoiderr_quit(char*msg){perror(msg);}int#include<unistd.h>#include<stdio.h>#include<stdlib.h>#include<fcntl.h>#include#defineBUFESvoiderr_quit(char*msg){perror(msg);}intmain(void{intcharbuf[BUFSZ]; /*緩沖*/pid_tpid;intifpipe(fd0)/*創(chuàng)建管道*/err_quit("pipe");ifif((pid=fork())<0elseif(pid==0close(fd[0]中write(fd[1],obrother!",14}if((pid=fork())<0)elseif(pid>0){close(fd[0]close(fd[1]exit(0}elseclose(fd[1]len=read(fd[0],buf,BUFS);write(STDOUT_FILENO,buf,len);}/*父進(jìn)中中消息}$gccbro_bro.c–o $./$./o上述序中父進(jìn)分別建立了2個(gè),在1中關(guān)閉了管道的讀出端,在子進(jìn)2中關(guān)閉了管道的輸入端,并在父進(jìn)中關(guān)閉了管道的兩端。注意:序中父進(jìn)在創(chuàng)建第1個(gè) 時(shí)并沒有關(guān)閉管道兩端,而是在創(chuàng)建第2個(gè)進(jìn)創(chuàng)建管道的標(biāo)準(zhǔn)庫(kù)函從序14-2和序14-3中可以總結(jié)出管道操作的一個(gè)流。父進(jìn)中先使用pipe函數(shù)創(chuàng)建管道,在調(diào)用fork函數(shù)創(chuàng)建,在父中管道的數(shù)據(jù)流向。序退出時(shí)及時(shí)關(guān)閉管道的兩端,具體流如圖14-4所示。圖14- 管道操作的基本流為:先創(chuàng)建一個(gè)管道,使用fork創(chuàng)建,在父中關(guān)閉不需要的文件描述符使用管道通信,序結(jié)束。由于這是一個(gè)比較規(guī)范也是比較常用的管道使用模式,所以在ANSI/ISOC中將以上操作定義在兩個(gè)標(biāo)準(zhǔn)的庫(kù)函數(shù)popen和pclose中,#include#includeFILE*popen(constchar*command,constchar*mode);intpclose(FILE*stream);函數(shù)popen的參數(shù)command是一個(gè)在s中可運(yùn)行令字符串的指針,參數(shù)mode是一個(gè)字符指針,這個(gè)參數(shù)只有兩種值可以使用,rwpopen函數(shù)的NULL,并設(shè)置出錯(cuò)變量errno。函數(shù)調(diào)用,調(diào)用/bin/sh–c來執(zhí)行參數(shù)command中令字符串,然后函數(shù)返回一個(gè)標(biāo)準(zhǔn)I/O文件指針。返回的文件指針類型與參數(shù)mode有關(guān)moder則文件指針commandwcommand命令的標(biāo)準(zhǔn)輸入。為了關(guān)popen函數(shù)返回的文件指針,可以pclose函數(shù)。pclose函數(shù)的參stream是一個(gè)popen打開的文件描述符,當(dāng)函數(shù)失敗返回–1。下面實(shí)例演示了使用popen和pclose函數(shù)實(shí)現(xiàn)調(diào)用s命令cat來打印一個(gè)文件到顯示器的序。序中先使用popen函數(shù)為cat命令創(chuàng)建一條數(shù)據(jù)管道,并指定數(shù)據(jù)管道從catfgets函數(shù)讀出數(shù)據(jù),并將數(shù)據(jù)顯示到標(biāo)準(zhǔn)#include<stdio.h>#include<fcntl.h>#defineBUFESPIPE_BUFintmain(void){FILEchar*cmd="catfile1";char*buf[BUFSZ];if((fp=popen(cmd,"r"))==NULL{perror("failedtopopen");exit(1);}/*創(chuàng)的whilefgets(bufBUFSZfpNULL)/*讀出管道的數(shù)據(jù)printf("%s",bufpclose(fp)exit(0)}序14-4recat.cpopenpclose函數(shù)創(chuàng)建管$gccrecat.c–o $./$./Usedthepopenandpclosefunctiontocreateapipe例如,popenread和writeI/OI/Opopenexec函數(shù)來復(fù)寫,這也是要花費(fèi)一段運(yùn)行時(shí)間的。FIFOstatst_mode成員的值來判斷文件是否是FIFO文件FIFO文件類似于創(chuàng)建文件,F(xiàn)IFO文件就像普通文件一樣。本小節(jié)將介紹FIFO管道。FIFO的概在本章14.2.2小節(jié)詳細(xì)說明了管道的缺點(diǎn)以及限制條件,在FIFO中可以很好地FIFO的通信方式類似于在進(jìn)中使用文件來傳輸數(shù)據(jù),只不過FIFO類型文件同時(shí)具有管道的特性。在數(shù)據(jù)讀出時(shí),F(xiàn)IFO管道中同時(shí)清除數(shù)據(jù)。在s中mkfifo命令可以建FIFO。mkfifo命令的幫助手冊(cè)如下所示:mkfifo[option] optionFIFO的模式,使用形式為-mmodemode指出將要?jiǎng)?chuàng)建FIFO的八進(jìn)制模式,注意,這里新創(chuàng)建的FIFO會(huì)像普通文件一樣受到創(chuàng)建進(jìn)的umask修正。在s中輸入命令如下:$mkfifo$mkfifo–m600$cat<$./recat$./recat#include<stdio.h>#include<fcntl.h>#defineBUFESintmain(void{FILEchar*cmd="catfile1";char*buf[BUFSZ];pclose(fp)exit(0)}以上實(shí)例使用系統(tǒng)命令mkfifo創(chuàng)建FIFO類型文件fifocat,并通過14.2.4節(jié)的序recat來文件recat.c,將序的標(biāo)準(zhǔn)輸出從定向到fifocat中,再使用命令cat從fifocat讀出創(chuàng)建FIFO文件類似于創(chuàng)建文件,F(xiàn)IFO文件就像普通文件一樣,也是可以經(jīng)過路徑名來的。相應(yīng)文件stat結(jié)構(gòu)的域st_mode的編碼指明了文件是否是FIFO類型。FIFO管道通過函數(shù)mkfifo創(chuàng)建,函數(shù)原型如下:#include<sys/stat.h>#include<sys/stat.h>intmkfifo(constchar*filename,mode_tmodemkfifo函數(shù)中參modeFIFO的讀寫權(quán)限FIFO的用戶ID和組ID規(guī)則LONG、ENOENT、ENOSPE、ENOTDIR和EROFS下面實(shí)例演示了如何使用mkfifo函數(shù)來創(chuàng)建一個(gè)FIFO。序中從序令行參數(shù)mkfifoFIFOFIFO只具有讀寫權(quán)限。由于FIFO文件的特性,所以它被隱性地規(guī)定不具有執(zhí)行權(quán)限。 14-5create_fifo.c使用mkfifo函數(shù)創(chuàng)建FIFO管#include<sys/stat.h>#include<errno.h>#include<stdio.h>#include<stdlib.h>intmain(intargc,char*argv[]{mode_tmode /*新創(chuàng)建的FIFO模式if(argc!=2/*向用戶提示序使用幫助printf("USEMSG:create_fifo{fifoname}\n");exit(1);}if((mkfifo(argv[1],mode))<{perror("failedtomkfifo");exit(1);}/*FIFOexit}$gcc$gcccreate_fifo.c–o$./$./USEMSG:create_fifo$./$./create_fifoyousuccessfullycreateaFIFOnameis$./create_fifofifo1mkfifo:Fileexists上述序使用mkfifo函數(shù)創(chuàng)建一個(gè)FIFO,名字是基于用戶的輸入文件名,可以看到當(dāng)要?jiǎng)?chuàng)建一個(gè)已經(jīng)存在的FIFO時(shí),序會(huì)產(chǎn)生一個(gè)EEXIST的異常,相對(duì)應(yīng)該異常,perror函數(shù)打印了相應(yīng)的幫助信息為mkfifo:Fileexists。FIFO的讀寫操openFIFO文件時(shí),openflagO_NONBLOCK標(biāo)志,它關(guān)系到函數(shù)的返回狀態(tài)。詳細(xì)說明如表14-2所示。14-2open函數(shù)的flag(O_NONBLOCK)詳細(xì)說write函數(shù)來進(jìn)行寫操作會(huì)產(chǎn)生信號(hào)SIGPIPE,則信號(hào)可以捉或者完全忽略。注意:當(dāng)FIFO的所有寫進(jìn)都已經(jīng)關(guān)閉,則為FIFO的讀進(jìn)產(chǎn)生一個(gè)文件結(jié)束符FIFO的出現(xiàn),極好地解決了系統(tǒng)在應(yīng)用過中產(chǎn)生的大量的中間臨時(shí)文件的問題。FIFO可以被s調(diào)用使數(shù)據(jù)從一個(gè)進(jìn)到另一個(gè)進(jìn),系統(tǒng)不必為該中間通道去煩惱清理不必要的,或者去釋放該通道的資源,它可以被留做后來的進(jìn)使用。并且規(guī)避下面實(shí)例演示了使用FIFO來進(jìn)行兩個(gè)進(jìn)間通信的例子。在序write_fifo.c中打開一個(gè)名為fifo1的FIFO文件,并分10次向這個(gè)FIFO中寫入數(shù)據(jù)。在序read_fifo.c中先打開fifo1文件,里面的數(shù)據(jù)并輸出到標(biāo)準(zhǔn)輸出中。#include<sys/stat.h>#include<errno.h>#include<stdio.h>#include<fcntl.h>#include<unistd.h>#include<stdlib.h>#include<limits.h>#defineBUFESint{intfd;intn,i;time_ttp;printf("Iam/*說明進(jìn)的if((fd=open("fifo1",O_WRONLY))<0){/*以寫打開一個(gè)}for(i=0;i<10; n=sprintf(buf,"write_fifo%dsendsprintf("Send 14-6write_fifo.c使用FIFO進(jìn)行通if((write(fd,if((write(fd,bufn+1))<0){/*FIFO中*/ /*FIFO} /*進(jìn)睡眠3秒} /*FIFO*/}openfifo1FIFO10fifo1中寫入字符串,其中的數(shù)據(jù)有當(dāng)前進(jìn)ID以及寫入時(shí)的系統(tǒng)時(shí)間。并把這個(gè)數(shù)據(jù)串輸出到標(biāo)準(zhǔn)輸出,然后序自動(dòng)睡眠3秒。#include<sys/stat.h>#include<unistd.h>#include<stdio.h>#include<stdlib.h>#include<limits.h>#include<fcntl.h>#include<unistd.h>#defineBUFESint{intfd;intcharbuf[BUFES];mode_tmode=0666;/*FIFO文件的權(quán)if((fd=open("fifo1",O_RDONLY))<0)/*FIFO{}while((len=read(fd,bufBUFES))>0*開始進(jìn)行通信*/printf("read_fiforead:%s",buf);序14-7read_fifo.cFIFOclose(fdclose(fd*FIFO*/}openfifo1FIFO管道,并循環(huán)讀出管道的默認(rèn)的是PIPE_BUF個(gè)字節(jié),當(dāng)管道中數(shù)據(jù)多于PIPE_BUF個(gè)字節(jié)時(shí),讀出PIPE_BUF-1個(gè)字節(jié),然后read函數(shù)返回,再打印數(shù)據(jù)到標(biāo)準(zhǔn)輸出。$gcc$gccwrite_fifo.c–o$gccread_fifo.c–o$mkfifo–m666 iam AprAprAprAprAprAprAprAprAprApr上述例子可以擴(kuò)展成客戶端與服務(wù)器通信的實(shí)例,write_fifo的作用類似于客戶端,可以打開多個(gè)客戶端向一個(gè)服務(wù)器發(fā)送請(qǐng)求信息,read_fifo類似于服務(wù)器,它適時(shí)著14-5FIFO在客戶端與服務(wù)器通信的應(yīng)FIFO的缺FIFO14-6所示??蛻舳丝梢园l(fā)請(qǐng)求到服務(wù)器,但前提是FIFO通道,對(duì)于實(shí)現(xiàn)服務(wù)器回傳應(yīng)答到客戶端的問題,可以通過為每FIFO是否會(huì)使系統(tǒng)負(fù)載過大,相應(yīng)的如何判斷客戶端是否因意外而成為難題,或者客戶端不應(yīng)答直接退出,所以服務(wù)器必須處理SIGPIPE說明:FIFO的時(shí)候,如果僅以讀打開,則當(dāng)所有的客戶端都退出時(shí),服務(wù)器端會(huì)到文件結(jié)束符。這個(gè)問題的解決辦法是服務(wù)器以讀寫打開公共FIFO,如圖14-6所示。服務(wù)器與客戶端如何實(shí)現(xiàn)互相通信。14-6FIFO在客戶端與服務(wù)器通信的應(yīng)SystemVIPC/POSIXSystemVIPC包括三種進(jìn)通信方式,即消息隊(duì)列、信號(hào)量以及共享器,這是一消息隊(duì)列、信號(hào)量以及共享器這三種IPC的幾種結(jié)構(gòu)有時(shí)又稱IPC對(duì)象,它不同于前面提到的管道和FIFO。管道和FIFO是基于文件系統(tǒng)的,例如,可在文件系統(tǒng)中看到某FIFOSystemVIPCipcs來查看系統(tǒng)當(dāng)前的IPC對(duì)象的狀態(tài),本節(jié)將詳細(xì)介紹它們各自的特點(diǎn)以及使用實(shí)例。IPC對(duì)象的概由于消息隊(duì)列、信號(hào)量以及共享器三種IPC有很多相類似的特性,所以本節(jié)將對(duì)它們的特性,以及相關(guān)知識(shí)做一些詳細(xì)的介紹,IPC對(duì)象示意圖如圖14-7所示。14-7IPC對(duì)象的應(yīng)用示意象通過它的標(biāo)識(shí)符來和,這個(gè)標(biāo)識(shí)符是一個(gè)非負(fù)整數(shù),它唯一的標(biāo)識(shí)了一個(gè)IPC對(duì)象,這個(gè)IPC對(duì)象可以是消息隊(duì)列或信號(hào)量或共享器中的任意一種類型。在Linux系統(tǒng)中標(biāo)識(shí)符被成整數(shù),所以可能存在的最大標(biāo)識(shí)符為65535。這里標(biāo)前進(jìn)最小可用的文件描述符數(shù)組的下標(biāo)。IPC對(duì)象刪除或創(chuàng)建時(shí)相應(yīng)的標(biāo)識(shí)符的值會(huì)不IPC對(duì)象還需要一個(gè)外部鍵(key),IPC對(duì)象都與一個(gè)鍵相關(guān)聯(lián)。這樣就解決了多進(jìn)在一個(gè)IPC對(duì)象上匯合的問題。創(chuàng)建一個(gè)IPC對(duì)象時(shí)需要指定一個(gè)鍵值,類型為key_t,在<sys/types.h>中定義為一個(gè)長(zhǎng)整型。鍵值到標(biāo)識(shí)符的轉(zhuǎn)換是由系統(tǒng)內(nèi)核來的。當(dāng)有了一個(gè)IPC對(duì)象的鍵值,如何可以使用文件來做中間的通道,創(chuàng)建IPC對(duì)象進(jìn),使用鍵IPC_PRIVATE成功建立IPC對(duì)象之后,將返回的標(biāo)識(shí)符在一個(gè)文件中。其他進(jìn)通過這個(gè)標(biāo)識(shí)符來IPC對(duì)象通信。定義一個(gè)多個(gè)進(jìn)都認(rèn)可的鍵,每個(gè)進(jìn)使用這個(gè)鍵來IPC對(duì)象,值得注意的是,創(chuàng)建IPC對(duì)象的進(jìn)中,創(chuàng)建IPC對(duì)象時(shí)如果該鍵值已經(jīng)與一個(gè)IPC對(duì)象結(jié)合,則應(yīng)該刪除該IPC對(duì)象,再創(chuàng)建一個(gè)新的IPC對(duì)象。多進(jìn)通信中,對(duì)于指定鍵一個(gè)IPC對(duì)象而言,可能不具有拓展性,并且在IPC對(duì)象結(jié)合的情況下。所以必須刪除這個(gè)存在對(duì)象之后再建立一個(gè)新的。這有可能影響到其他正在使用這個(gè)對(duì)象的進(jìn)。函數(shù)ftok可以在一#include#includekey_tftok(constchar*path,intid函數(shù)中參數(shù)path是一個(gè)文件名。函數(shù)中進(jìn)行的操作是,取該文件的stat結(jié)構(gòu)的st_devst_inoID的第八位結(jié)合起來生成一個(gè)鍵值。由于只是st_dewst_inoID,系統(tǒng)為每一個(gè)IPC對(duì)象保存一個(gè)ipc_perm結(jié)構(gòu)結(jié)構(gòu)說明了IPC對(duì)象的權(quán)限和所<sys/ipc.h>structstruct{key_tkey;uid_tuid;gid_tgid;uid_tcuid;gid_tcgid;unsignedshortmode;unsignedshortseq;每一種版本的ipc_perm結(jié)構(gòu)體定義至少要包含上述幾個(gè)域。當(dāng)調(diào)用IPC對(duì)象(semgetmsggetshmget)ipc_perm結(jié)構(gòu)的每一個(gè)域賦值。在后續(xù)的操作中如需修改這幾個(gè)域則調(diào)用相應(yīng)的控制函數(shù)(msgctlsemctlshmctl)。注意:只有超級(jí)用戶或者創(chuàng)建IPC對(duì)象的進(jìn)改變ipc_perm結(jié)構(gòu)的值。結(jié)構(gòu)中的modestatmode域,但是不可以有執(zhí)行權(quán)限。mode值描述如表14-3所示。14-3ipc_perm的mode讀寫(更改更新讀寫(更改更新組IPC對(duì)象的問IPC對(duì)象。為此不得不新增加一些函數(shù)來支持必要的一些操作(例如msggetmsgrevmsgctl等)IPC對(duì)象都有一系列特定的操作函數(shù)。由于IPC不使用文件描述符,所以不能使用多路I/O函數(shù)select及poll函數(shù)來操作IPC對(duì)象。缺少的資源回收機(jī)制。由于IPC對(duì)象在使用過中并不保存計(jì)數(shù),所以當(dāng)出現(xiàn)一個(gè)進(jìn)創(chuàng)建了IPC對(duì)象然后退出時(shí),則這個(gè)對(duì)象只有在出現(xiàn)后面幾種情況才會(huì)被釋放或者刪除,即由某一個(gè)進(jìn)讀出消息,或者IPC的所有者或超級(jí)用戶刪除了這個(gè)對(duì)象。這也是IPC相對(duì)于管道或FIFO所欠缺的資源回收機(jī)制。IPC對(duì)象系統(tǒng)命在s下可以使用一些命令來操作IPC對(duì)象,下面通過幾個(gè)實(shí)際的例子來幫助理------MessageQueues------- used- ------MessageQueues------- used- $ipcs------SharedMemorySegments-------200------SemaphoreArrays-------1$ipcs------SharedMemorySegments-------------SemaphoreArrays------- 1------MessageQueues------- used- $ipcs------SharedMemorySegments-------------SemaphoreArrays------- 1------MessageQueues------- used- 20則應(yīng)檢查系統(tǒng)IPC狀態(tài),并使用ip命令刪除不使用的IPC。于內(nèi)核級(jí)別的一種資源,在s中可以使用ipcs命令來查看當(dāng)前系統(tǒng)IPC中的狀態(tài),在文件系統(tǒng)中/proc下有對(duì)其描述的相應(yīng)文件。共享內(nèi)存的概件<sys/shm.h>中。shmid_ds結(jié)構(gòu)體定義如下:14-8共享內(nèi)存示意structstruct/ 共享內(nèi)存的創(chuàng)共享內(nèi)存是存在于內(nèi)核級(jí)別的一種資源,在s中可以使用ipcs命令來查看當(dāng)前系IPC中的狀態(tài),在文件系統(tǒng)/procshmget可以創(chuàng)建#include#includeintshmget(key_tkey,size_tsize,intflag函數(shù)中參數(shù)key用來變換成一個(gè)標(biāo)識(shí)符,而且每一個(gè)IPC對(duì)象與一個(gè)key相對(duì)應(yīng)。當(dāng)新建一個(gè)共享內(nèi)存段時(shí),size參數(shù)為要請(qǐng)求的內(nèi)存長(zhǎng)度(以字節(jié)為單位)。注意:size參數(shù)的值不是系統(tǒng)內(nèi)存頁(yè)長(zhǎng)的整數(shù)倍時(shí),系統(tǒng)當(dāng)打開一個(gè)內(nèi)存段時(shí),參數(shù)size的值為0。參數(shù)flag中的相應(yīng)權(quán)限位初始化ipc_permmodeflag是函數(shù)行為參數(shù),它指定一些當(dāng)函數(shù)遇到阻塞或其他情況時(shí)應(yīng)做出的反應(yīng)。shmid_ds結(jié)構(gòu)初始化如表14-4所示。14-4shmid_ds的初始 0000參數(shù)下面實(shí)例演示了使用shmget函數(shù)創(chuàng)建一塊共享內(nèi)存。序中在調(diào)用shmget函數(shù)時(shí)指定key參數(shù)值為IPC_PRIVATE,這個(gè)參數(shù)的意義是創(chuàng)建一個(gè)新的共享內(nèi)存區(qū),當(dāng)創(chuàng)建成功后使用s命令ipcs來顯示目前系統(tǒng)下共享內(nèi)存的狀態(tài)。命令參數(shù)-m為只顯示共享內(nèi)存的#include<sys/ipc.h>#include<sys/shm.h>#include<stdlib.h>#include<stdio.h>#defineBUFSZintmain(void{int#include<sys/ipc.h>#include<sys/shm.h>#include<stdlib.h>#include<stdio.h>#defineBUFSZintmain(void{int shm_id=shmget(IPC_PRIVATE,BUFSZ0666if(shm_id<0){/*創(chuàng)建共享內(nèi)存*/perror("shmget");exit(1);}printfsuccessfullycreatedsegment%dnshm_idsystem("ipcs-m"); /*調(diào)用ipcs命令查看IPC*/exit(0}$gcccreate_shm.c–o $./ successfullycreatedsegment------SharedMemorySegments-------201105656共享內(nèi)存的操用函數(shù)shmctl可以對(duì)共享內(nèi)存段進(jìn)行多種操作,其函數(shù)原型如下:#include#includeintshmctl(intshm_id,intcmd,structshmid_ds*bufcmdcmd14-5所示。14-5shmctl函數(shù)中參數(shù)cmd詳cmd的 使用buf指向的結(jié)構(gòu)對(duì)sh_mid段的相關(guān)結(jié)構(gòu)賦值,只對(duì)以下幾個(gè)域有作用uidshm_perm.gidshm_perm#include#includevoid*shmat(intshm_id,constvoid*addr,intflag shm_idaddrflag組合說明要引入的地址不會(huì)只對(duì)一種硬件上運(yùn)行應(yīng)用序,為了序的通用薦使用第1種方法),在flag參說明:函數(shù)成功執(zhí)行返回值為實(shí)際引入的地址,失敗返回–1。 函數(shù)成功執(zhí)行會(huì)#include#includeintshmdt(void參數(shù)addr是調(diào)用shmat函數(shù)的返回值,函數(shù)執(zhí)行成功返回0,并將該共享內(nèi)存的shmid_ds結(jié)構(gòu)的shm_nattch計(jì)數(shù)器減1,失敗返回–1。函數(shù)引入該共享內(nèi)存,并在分離該內(nèi)存之前睡眠3秒以方便查看系統(tǒng)IPC狀態(tài)。#include<sys/ipc.h>#include<sys/shm.h>#include<stdlib.h>#include<stdio.h>intmain(intargc,char*argv[]{intshm_id;char*shm_buf;ifargc2*命令行參數(shù)錯(cuò)printf("USAGE:atshm<identifier>"); exit(1);}shm_id=if((shm_buf=shmat(shm_id,0,0))<(char*)0perror("shmat"序14-9opr_shm.cexitexit}printf("segmentattachedat%p\n",shm_buf); system("ipcs-m");/*ifshmdt(shm_buf0/*與導(dǎo)入的共享內(nèi)存段分離perror("shmdt");}printf("segmentdetached\n"systemipcsm /*再次查看系統(tǒng)IPC狀態(tài)exit(0}$gccopr_shm.c–o $./segmentattachedat------SharedMemorySegments-------20111segment------Shared------- 20110上述序中從命令行中所要引入的共享內(nèi)存ID,并使用shmat函數(shù)引入該內(nèi)存到當(dāng)前的進(jìn)空間中。注意在使用shmat函數(shù)時(shí),將參數(shù)addr的值設(shè)為0,所表達(dá)的意義是特定的硬件或系統(tǒng)編,所以由內(nèi)核決定引入位置也就是shmat推薦的使用方式。在導(dǎo)入后使用s 共享內(nèi)存使用注意事共享內(nèi)存相比其他幾種方式有著更方便的數(shù)據(jù)控制能力,數(shù)據(jù)在讀寫過中會(huì)更透進(jìn)下用戶可以隨意的。缺點(diǎn)是,數(shù)據(jù)寫入進(jìn)或數(shù)據(jù)讀出進(jìn)中,需要附加的數(shù)據(jù)14-914-9共享內(nèi)存通信數(shù)據(jù)結(jié)構(gòu)示說明:圖中兩個(gè)進(jìn)同時(shí)遵循一定的規(guī)則來讀寫該內(nèi)存。同時(shí),在多進(jìn)同步或互斥上信號(hào)信號(hào)量的資源是否可用。當(dāng)信號(hào)量的值大于0時(shí),表明有資源可以請(qǐng)求。等于0時(shí),說明現(xiàn)在無可當(dāng)進(jìn)不再使用一個(gè)信號(hào)量控制的共享資源時(shí),此信號(hào)量的值增1,對(duì)信號(hào)量的值進(jìn)同其他的IPC對(duì)象一樣,內(nèi)核對(duì)每一個(gè)信號(hào)量集都會(huì)設(shè)置一個(gè)shmid_ds結(jié)構(gòu)(詳細(xì)structstructunsignedshortsemval; unsignedshortsemncent;unsignedshort }信號(hào)量的semctl等ipcsIPC的狀態(tài),在命令后使用-s參數(shù)。使用函數(shù)semget可以創(chuàng)建或者獲得一個(gè)信號(hào)量集ID,函數(shù)原型如下:#include#includeintsemget(key_tkey,intnsems,int函數(shù)中參數(shù)key用來變換成一個(gè)標(biāo)識(shí)符,每一個(gè)IPC對(duì)象與一個(gè)key相對(duì)應(yīng)。當(dāng)新建一個(gè)共享內(nèi)存段時(shí),使用參數(shù)flag的相應(yīng)權(quán)限位對(duì)ipc_perm結(jié)構(gòu)中的mode域賦值,對(duì)相應(yīng)信號(hào)量集的shmid_ds初始化的值如表14-6所示。14-6shmid_ds結(jié)構(gòu)初始化值 0nsems0的值,用于指明該信號(hào)量集中可用資源數(shù)(在創(chuàng)建一個(gè)#include#includeintsemop(intsemid,structsembufsemoparray[],size_tnops semidsemgetnops標(biāo)明型的數(shù)組指針,結(jié)構(gòu)sembuf來說明所要執(zhí)行的操作,其定義如下:structstructunsignedshort;}在sembuf結(jié)構(gòu)中,sem_num是相對(duì)應(yīng)的信號(hào)量集中的某一個(gè)資源,所以其值是一個(gè)0到相應(yīng)的信號(hào)量集的資源總數(shù)(ipc_perm.sem_nsems)之間的整數(shù)。sem_op指明所要執(zhí)行的操作,sem_說明函數(shù)semop的行為。sem_op的值是一個(gè)整數(shù),如表14-7所示,列出了詳細(xì)sem_op的值及所對(duì)應(yīng)的操作。14-7sem_op 0進(jìn)阻塞直到信號(hào)量的相應(yīng)值為0,當(dāng)信號(hào)量已經(jīng)為0,函數(shù)立即返回。如果信號(hào)量的值不為0,則依據(jù)sem_的IPC_NOWAIT位決定函數(shù)動(dòng)作。sem_指定IPC_NOWAIT,則semop函數(shù)出錯(cuò)返回EAGAIN。sem_沒有指定IPC_NOWAIT,則將該信號(hào)量的t值加1,然后進(jìn)掛起直到下述情況發(fā)生。信號(hào)量值為0,將信號(hào)量的 t的值減1,函數(shù)semop成功返回;此信號(hào)量被刪除(只有超級(jí)用戶或創(chuàng)建用戶進(jìn)擁有此權(quán)限),函數(shù)smeop出錯(cuò)返回EIDRM;進(jìn)捕捉到信號(hào),并從信號(hào)處理函數(shù)返回,在此情 請(qǐng)求sem_op的絕對(duì)值的資源。如果相應(yīng)的資源數(shù)可以滿足請(qǐng)求,則將該信號(hào)量的值減去sem_op的絕對(duì)值,函數(shù)成功返回。當(dāng)相應(yīng)的資源數(shù)不能滿足請(qǐng)求時(shí),這個(gè)操作與sem_有關(guān)。sem_指定IPC_NOWAIT,則semop函數(shù)出錯(cuò)返回EAGAIN。sem_沒有指定 t值加1,然后進(jìn)掛起直到下述情況發(fā)生:當(dāng)相應(yīng)的資源數(shù)可以滿足請(qǐng)求,該信號(hào)的值減去sem_op的絕對(duì)值。成功返回;此信號(hào)量被刪除(只有超級(jí)用戶或創(chuàng)建用戶進(jìn)擁有此權(quán)限),函數(shù)smeop出錯(cuò)返回EIDRM:進(jìn)捕 t值減1,函數(shù)semop集,并使用semop函數(shù)在這個(gè)信號(hào)集上執(zhí)行了一次資源釋放操作。并在s中使用命令查看系統(tǒng)IPC的狀態(tài)。在vi編輯器中編輯該序#include<sys/ipc.h>#include<sys/sem.h>#include<stdio.h>#include 14-10create_sem.c使用semget函數(shù)創(chuàng)建#include<sys/ipc.h>#include<sys/sem.h>#include<stdio.h>#includeintintmain(void{intsem_id;intnsems=1;intflags=0666;structsembufbuf;sem_id=semget(IPC_PRIVATE,nsems,if(sem_id0){perror("semget");exit(1);}printf("successfullycreatedasemaphore:%d\n",sem_idbuf.sem_num=buf.sem_op==/*semop函數(shù)的行為if((semop(sem_id,&buf,nsems))<{perror("semop");exit(1);}system("ipcs-s"exit(0/*IPC狀態(tài)}$gcccreate_sem.c–o $./$./------SemaphoreArrays-------- 1successfullycreatedasemaphore:在上面序中,用semget函數(shù)創(chuàng)建了一個(gè)信號(hào)量集,定義信號(hào)量集的資源數(shù)為1,接下來使用semop函數(shù)進(jìn)行資源釋放操作。在序的最后使用s命令ipcs來查看系統(tǒng)IPC的信號(hào)量集的操IPC對(duì)象類型中,信號(hào)量集的操作函數(shù)相對(duì)于其他兩個(gè)類型的操作函數(shù)要復(fù)雜得的專屬操作函數(shù)semctl,函數(shù)原型如下:#include#includeintsemctl(intsem_id,intsemnu,intcmd[,unionsemun函數(shù)所要進(jìn)行的操作。其取值以及表達(dá)的意義如表14-8所示。14-8cmd值詳cmd的取 T tT tsemun{intunsignedshort*buf下面實(shí)例演示了如何使用semctl函數(shù)。序中先使用semget函數(shù)創(chuàng)建了一個(gè)新的信號(hào)量集,然后通過s命令查看系統(tǒng)IPC的狀態(tài),再調(diào)用一次semctl函數(shù)做刪除操作,并查看系統(tǒng)IPC的狀態(tài)#include 14-11ctl_sem.c使用semctl刪除信號(hào)#include#include<sys/ipc.h>#include<stdio.h>#include<stdlib.h>intmain(void{intsem_id;intnsems=1;intflags=semidsemgetIPC_PRIVATEnsemsflags*創(chuàng)建一個(gè)信號(hào)量集if(sem_id<0){perror("semget");(1/*printf("successfullycreatedasemaphore:%d\n",sem_id/*輸出創(chuàng)建的信號(hào)量的IDsystem("ipcs-s"/*IPC狀態(tài)if((semctl(semid,0,IPC_RMID))<0{perror("semctl");exit(1);}elseprintf("semaphoreremoved\n");system("ipcs-s");}/*刪除指定信號(hào)量集/*IPC狀態(tài)exit(0}$gccctl_sem.c–o $./------SemaphoreArrays-------111successfullycreatedasemaphore:SemaphoreArrays--- ---10x0056a4d51semaphore在 $./ –s<semaphoresemid> 說明:上述序中,使用semget函數(shù)創(chuàng)建一個(gè)信號(hào)量時(shí),有可能系統(tǒng)中已經(jīng)有了一個(gè)跟IPC_PRIVATE鍵關(guān)聯(lián)的信號(hào)量,此時(shí)應(yīng)在 中先刪除該IPC,然后再運(yùn)消息隊(duì)列是一種以鏈表式結(jié)構(gòu)組織的一組數(shù)據(jù),存放在內(nèi)核中,是由各進(jìn)通過消息隊(duì)列標(biāo)識(shí)符來的一種數(shù)據(jù)傳送方式。像其他兩種IPC對(duì)象一樣,也是由內(nèi)核來。IPC對(duì)象類型中最具有數(shù)據(jù)操作性的數(shù)據(jù)傳送方式,在消息隊(duì)列中可以隨消息隊(duì)列的概消息隊(duì)列是一個(gè)消息的表,該表由內(nèi)核進(jìn)行及。消息隊(duì)列相比其他的通流的概念上擴(kuò)展了數(shù)據(jù)傳送的概念,可以根據(jù)需要只指定數(shù)據(jù),該點(diǎn)是管道和FIFOID分別指消息隊(duì)列和消息隊(duì)列描述符。消息隊(duì)列在多進(jìn)間通信示意如圖14-10所示。14-10消息隊(duì)列示意對(duì)于每個(gè)隊(duì)列都有一個(gè)msqid_ds結(jié)構(gòu)體來描述隊(duì)列當(dāng)前的狀態(tài)。該結(jié)構(gòu)體定msqid_ds{ 說明:在不同的系統(tǒng)中,此結(jié)構(gòu)會(huì)有不同的新成員,這里只列出最少擁有的關(guān)鍵成員。創(chuàng)建消息IPC對(duì)象類型中最具有數(shù)據(jù)操作性的數(shù)據(jù)傳送方式,在消息隊(duì)列中可#include#includeintmsgget(key_tkey,intmsggetfalgs指定IPC_CREAT|06660666的消息隊(duì)列,其中組用戶、當(dāng)前用戶以及#include<sys/msg.h>#include<sys/ipc.h>#include<stdio.h>#include<stdlib.h>intmain(void#include<sys/msg.h>#include<sys/ipc.h>#include<stdio.h>#include<stdlib.h>intmain(void{ key=qid=msgget(key,IPC_CREAT|0666if(qid<0)perror("msgget");exit(1);}/*printf"createdqueueiddnqid*IDsystem("ipcs-q"exit(0/*IPC的狀態(tài)}$gcc$gcccreate_msg.c–o0x0000af4000 b00#includeintmsgctl(intmsqid,intcmd,structmsqid_ds*buf$./create_msgcreatedqueueid:0------MessageQueues------- used- 在序中使用了系統(tǒng)命令ipcs#includeintmsgctl(intmsqid,intcmd,structmsqid_ds*buf$./create_msgcreatedqueueid:0------MessageQueues------- used- msqid為指定的要操作的隊(duì)列,cmd參數(shù)指定所要進(jìn)行的操作,其中有些操作需要buf參數(shù)。cmd參數(shù)的詳細(xì)取值及操作如表14-9所示。14-9cmd參數(shù)詳 msg_perm.gid、msg_permmodemsg_perm.cuid。該命令只能由具有以下條件的進(jìn)執(zhí)行:進(jìn)有效用戶ID等于msg_perm.cuid或msg_perm.uid超級(jí)用戶進(jìn)。其中只該命令只能由具有以下條件的進(jìn)執(zhí)行。進(jìn)有效用戶ID等于msg_perm.cuid或msg_perm.uid印命令提示信息,在調(diào)用msgctl函數(shù)執(zhí)行刪除操作的前后分別調(diào)用了一次s命令ipcs–q來查看系統(tǒng)IPC的狀態(tài)。#include<sys/msg.h>#include<sys/ipc.h>#include<stdio.h>#include<stdlib.h>intmain(intargc,char*#include<sys/msg.h>#include<sys/ipc.h>#include<stdio.h>#include<stdlib.h>intmain(intargc,char*argv[]{intqidifargc2*命令行參數(shù)出puts("USAGE:del_msgq.c<queueID>");exit(1);}qidatoiargv[1*通過命令行參數(shù)得到ID*/system("ipcs-q");ifmsgctl(qidIPC_RMIDNULL0*刪除指定的消息隊(duì)列*/perror("msgctl");exit(1}system("ipcs-printfsuccessfullyremoveddqueue\nqid*刪除隊(duì)列成功exit(0}$gccdel_msg.c–o $./------MessageQueues-------used-b00------MessageQueues------- used- successfullyremoved0 讀寫消息由于消息隊(duì)列的特殊性,系統(tǒng)為這個(gè)數(shù)據(jù)類型提供了兩個(gè)接口(msgsnd函數(shù),msgrcv#include#includeintmsgsnd(intmsqid,constvoid*prt,siz
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年能源管理與企業(yè)節(jié)能策略
- 第2單元雙休必讀經(jīng)典書
- 2026年劇本殺運(yùn)營(yíng)公司質(zhì)量問題整改管理制度
- 2026年劇本殺運(yùn)營(yíng)公司員工跨部門培訓(xùn)管理制度
- 生成式人工智能在初中歷史課堂個(gè)性化教學(xué)中的應(yīng)用探討教學(xué)研究課題報(bào)告
- 高中生對(duì)基因編輯技術(shù)科學(xué)證據(jù)的批判性思維訓(xùn)練課題報(bào)告教學(xué)研究課題報(bào)告
- 護(hù)理部護(hù)理工作信息化建設(shè)匯報(bào)
- 健全消防安全制度
- 體育消費(fèi)券制度
- 會(huì)員管理制度
- 2025中國(guó)機(jī)械工業(yè)集團(tuán)有限公司國(guó)機(jī)集團(tuán)總部社會(huì)招聘19人筆試參考題庫(kù)附帶答案詳解
- 城鎮(zhèn)老舊供水管網(wǎng)及附屬設(shè)施升級(jí)改造工程節(jié)能評(píng)估報(bào)告
- 紀(jì)委監(jiān)委辦案安全課件
- 2026年全國(guó)婦聯(lián)所屬在京事業(yè)單位公開招聘?jìng)淇碱}庫(kù)含答案詳解
- 2025年輸血知識(shí)考試試題及答案
- 2025-2026學(xué)年人教版八年級(jí)上冊(cè)道德與法治期末試卷(含答案和解析)
- 幼兒園消防安全管理細(xì)則解讀
- 沈陽(yáng)市2025遼寧沈陽(yáng)市于洪區(qū)社區(qū)殘疾人工作專職干事招聘筆試歷年參考題庫(kù)典型考點(diǎn)附帶答案詳解(3卷合一)
- 2026年內(nèi)蒙古電子信息職業(yè)技術(shù)學(xué)院?jiǎn)握新殬I(yè)適應(yīng)性測(cè)試題庫(kù)附答案詳解
- 2025年綿陽(yáng)市中考英語(yǔ)試題(附答案)
- T-CASEI 026-2023 在役立式圓筒形鋼制焊接儲(chǔ)罐安全附件檢驗(yàn)技術(shù)標(biāo)準(zhǔn)
評(píng)論
0/150
提交評(píng)論