精品专区-精品自拍9-精品自拍三级乱伦-精品自拍视频-精品自拍视频曝光-精品自拍小视频

網(wǎng)站建設(shè)資訊

NEWS

網(wǎng)站建設(shè)資訊

Linux的管道是什么

本篇內(nèi)容主要講解“Linux的管道是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Linux的管道是什么”吧!

專注于為中小企業(yè)提供網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)畢節(jié)免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了上1000家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。

管道是Linux由Unix那里繼承過來的進(jìn)程間的通信機(jī)制,它是Unix早期的一個(gè)重要通信機(jī)制。其思想是,在內(nèi)存中創(chuàng)建一個(gè)共享文件,從而使通信雙方利用這個(gè)共享文件來傳遞信息。由于這種方式具有單向傳遞數(shù)據(jù)的特點(diǎn),所以這個(gè)作為傳遞消息的共享文件就叫做“管道”。

在管道的具體實(shí)現(xiàn)中,根據(jù)通信所使用的的文件是否具有名稱,有“匿名管道”和“命名管道”。

管道與共享內(nèi)存的區(qū)別
乍一看,感覺管道和共享內(nèi)存并不是區(qū)別很大,這里介紹一下兩者之間的區(qū)別:

管道需要在內(nèi)核和用戶空間進(jìn)行四次的數(shù)據(jù)拷貝:由用戶空間的buf中將數(shù)據(jù)拷貝到內(nèi)核中 -> 內(nèi)核將數(shù)據(jù)拷貝到內(nèi)存中 -> 內(nèi)存到內(nèi)核 -> 內(nèi)核到用戶空間的buf。而共享內(nèi)存則只拷貝兩次數(shù)據(jù):用戶空間到內(nèi)存 -> 內(nèi)存到用戶空間。
管道用循環(huán)隊(duì)列實(shí)現(xiàn),連續(xù)傳送數(shù)據(jù)可以不限大小。共享內(nèi)存每次傳遞數(shù)據(jù)大小是固定的;
共享內(nèi)存可以隨機(jī)訪問被映射文件的任意位置,管道只能順序讀寫;
管道可以獨(dú)立完成數(shù)據(jù)的傳遞和通知機(jī)制,共享內(nèi)存需要借助其他通訊方式進(jìn)行消息傳遞。
也就是說,兩者之間最大的區(qū)別就是: 共享內(nèi)存區(qū)是最快的可用IPC形式,一旦這樣的內(nèi)存區(qū)映射到共享它的進(jìn)程的地址空間,這些進(jìn)程間數(shù)據(jù)的傳遞,就不再通過執(zhí)行任何進(jìn)入內(nèi)核的系統(tǒng)調(diào)用來傳遞彼此的數(shù)據(jù),節(jié)省了時(shí)間。

匿名管道
匿名管道是在具有公共祖先的進(jìn)程之間進(jìn)行通信的一種方式。

前面在介紹進(jìn)程的創(chuàng)建時(shí)講到,由父進(jìn)程創(chuàng)建的子進(jìn)程將會(huì)賦值父進(jìn)程包括文件在內(nèi)的一些資源。如果父進(jìn)程創(chuàng)建子進(jìn)程之前創(chuàng)建了一個(gè)文件,那么這個(gè)文件的描述符就會(huì)被父進(jìn)程在隨后所創(chuàng)建的子進(jìn)程所共享。也就是說,父、子進(jìn)程可以通過這個(gè)文件進(jìn)行通信。如果通信的雙方一方只能進(jìn)行讀操作,而另一方只能進(jìn)行寫操作,那么這個(gè)文件就是一個(gè)只能單方向傳送消息的管道,如下圖所示:

進(jìn)程可以通過調(diào)用函數(shù)pipe()創(chuàng)建一個(gè)管道。函數(shù)pipe()的原型如下:

int pipe(int fildes[2]);
與該函數(shù)pipe()相對(duì)應(yīng)的系統(tǒng)調(diào)用sys_pipe()的原型如下:

asmlinkage int sys_pipe(unsigned long __user * fildes);
從本質(zhì)上來說,pipe()函數(shù)的功能就是創(chuàng)建一個(gè)內(nèi)存文件,但與創(chuàng)建普通文件的函數(shù)不同,函數(shù)pipe()將在參數(shù)fildes中為進(jìn)程返回這個(gè)文件的兩個(gè)文件描述符fildes[0]和fildes[1]。其中,fildes[0]是一個(gè)具有“只讀”屬性的文件描述符,fildes[1]是一個(gè)具有“只寫”屬性的文件描述符,即進(jìn)程通過fildes[0]只能進(jìn)行文件的讀操作,而通過fildes[1]只能進(jìn)行文件的寫操作。

這樣,就使得這個(gè)文件像一段只能單向流通的管道一樣,一頭專門用來輸入數(shù)據(jù),另一頭專門用來輸出數(shù)據(jù),所以稱為管道。由于這種文件沒有文件名,不能被非親進(jìn)程所打開,只能用于親屬進(jìn)程間的通信,所以這種沒有名稱的文件形成的通信管道叫做“匿名管道”。

顯然,如果父進(jìn)程創(chuàng)建的這種文件只是用來通信,那么它感興趣的只是該文件所占用的內(nèi)存空間,所以也就沒有必要?jiǎng)?chuàng)建一個(gè)正式文件,只需創(chuàng)建一個(gè)只存在于內(nèi)存的臨時(shí)文件。從這一點(diǎn)來看,匿名管道與共享內(nèi)存具有共同點(diǎn),只不過匿名管道時(shí)單向通信,而且這個(gè)通信只能在親屬進(jìn)程間進(jìn)行。

為支持匿名管道,內(nèi)核初始化時(shí)由內(nèi)核函數(shù)kernel_mount()安裝了一種特殊的文件系統(tǒng),在該系統(tǒng)中所創(chuàng)建的都是臨時(shí)文件。

由于匿名管道是一個(gè)文件,所以它也有i節(jié)點(diǎn),其結(jié)構(gòu)如下:

struct inode
{
        ...
        struct file_operations *i_fop;            //文件操作函數(shù)集
        struct pipe_inode_info *i_pipe;           //管道文件指針
        ...
};
可以看到,在i節(jié)點(diǎn)的結(jié)構(gòu)中有一個(gè)pipe_inode_info類型的指針i_pipe,在普通文件中這個(gè)指針的值為NULL,而在管道文件中這個(gè)指針則只想一個(gè)叫做管道節(jié)點(diǎn)信息結(jié)構(gòu)的pipe_inode_info,以表明這是一個(gè)管道文件。pipe_inode_info的結(jié)構(gòu)如下:

struct pipe_inode_info {
    wait_queue_head_t wait;            //等待進(jìn)程隊(duì)列
    unsigned int nrbufs, curbuf;
    struct page *tmp_page;
    unsigned int readers;
    unsigned int writers;
    unsigned int waiting_writers;
    unsigned int r_counter;            //以只讀方式訪問管道的進(jìn)程計(jì)數(shù)器
    unsigned int w_counter;            //以只寫方式訪問管道的進(jìn)程計(jì)數(shù)器
    struct fasync_struct *fasync_readers;
    struct fasync_struct *fasync_writers;
    struct inode *inode;
    struct pipe_buffer bufs[PIPE_BUFFERS];            //緩沖區(qū)數(shù)組
};
結(jié)構(gòu)中的域bufs就是構(gòu)成管道的內(nèi)存緩沖區(qū)。該緩沖區(qū)用結(jié)構(gòu)pipe_buffer來描述:

struct pipe_buffer {
    struct page *page;                    //緩沖頁的結(jié)構(gòu)
    unsigned int offset, len;
    const struct pipe_buf_operations *ops;            //緩沖區(qū)的操作函數(shù)集指針
    unsigned int flags;
    unsigned long private;
};
從上面的數(shù)據(jù)結(jié)構(gòu)中可以看到,管道實(shí)質(zhì)上就是一個(gè)被當(dāng)做文件來管理的內(nèi)存緩沖區(qū)。

在創(chuàng)建一個(gè)管道的i節(jié)點(diǎn)時(shí),結(jié)構(gòu)inode中的域i_fop被賦予rdwr_pipefifo_fops,即管道文件本身是既可讀又可寫的。rdwr_pipefifo_fops在文件linux/fs/pipe.c中的定義如下:

const struct file_operations rdwr_pipefifo_fops = {
    .llseek        = no_llseek,
    .read        = do_sync_read,
    .aio_read    = pipe_read,
    .write        = do_sync_write,
    .aio_write    = pipe_write,
    .poll        = pipe_poll,
    .unlocked_ioctl    = pipe_ioctl,
    .open        = pipe_rdwr_open,
    .release    = pipe_rdwr_release,
    .fasync        = pipe_rdwr_fasync,
};
而為進(jìn)程所創(chuàng)建的打開文件描述符fildes[0]和fildes[1]中的i_fop,則被分別賦予了只讀的函數(shù)操作集read_pipefifo_fops和只寫的函數(shù)操作集write_pipefifo_fops。

read_pipefifo_fops和write_pipefifo_fops這兩個(gè)操作函數(shù)集在文件linux/fs/pipe.c中分別定義如下:

const struct file_operations read_pipefifo_fops = {
    .llseek        = no_llseek,
    .read        = do_sync_read,
    .aio_read    = pipe_read,
    .write        = bad_pipe_w,
    .poll        = pipe_poll,
    .unlocked_ioctl    = pipe_ioctl,
    .open        = pipe_read_open,
    .release    = pipe_read_release,
    .fasync        = pipe_read_fasync,
};
 
const struct file_operations write_pipefifo_fops = {
    .llseek        = no_llseek,
    .read        = bad_pipe_r,
    .write        = do_sync_write,
    .aio_write    = pipe_write,
    .poll        = pipe_poll,
    .unlocked_ioctl    = pipe_ioctl,
    .open        = pipe_write_open,
    .release    = pipe_write_release,
    .fasync        = pipe_write_fasync,
};
創(chuàng)建匿名管道的進(jìn)程與管道之間的關(guān)系如下圖所示:

當(dāng)一個(gè)進(jìn)程調(diào)用函數(shù)pipe()創(chuàng)建一個(gè)管道后,管道的連接方式如下所示:

從圖中可以看到,由于管道的出入口都在同一個(gè)進(jìn)程之中,這種管道沒有多大的用途的。但是當(dāng)這個(gè)進(jìn)程在創(chuàng)建一個(gè)新進(jìn)程之后,情況就變得大不一樣了。

如果父進(jìn)程創(chuàng)建一個(gè)管道之后,又創(chuàng)建了一個(gè)子進(jìn)程,那么由于子進(jìn)程繼承了父進(jìn)程的文件資源,于是管道在父子進(jìn)程中的連接情況就變成如下圖一樣的情況了:

在確定管道的傳輸方向之后,在父進(jìn)程中關(guān)閉(close())文件描述符fildes[0],在子進(jìn)程中關(guān)閉(close())文件描述符fildes[1],于是管道的連接情況就變成如下情況的單向傳輸管道:

也可以想象,通過關(guān)閉文件描述符的方法,在兩個(gè)兄弟進(jìn)程之間也可以實(shí)現(xiàn)通信管道。

創(chuàng)建完管道之后,怎么利用管道來進(jìn)行數(shù)據(jù)的通信呢?

管道使用read()和write()函數(shù),采用字節(jié)流的方式,具有流動(dòng)性,讀數(shù)據(jù)時(shí),每讀一段數(shù)據(jù),則管道內(nèi)會(huì)清除已讀走的數(shù)據(jù)。

讀管道時(shí),若管道為空,則被堵塞,直至管道另一端write將數(shù)據(jù)寫入到管道為止。若寫段已關(guān)閉,則返回0;
寫管道時(shí),若管道已滿,則被阻塞,直到管道另一端read將管道內(nèi)數(shù)據(jù)取走為止。
用close()函數(shù),在創(chuàng)建管道時(shí),寫端需要關(guān)閉fildes[0]描述符,讀端需要關(guān)閉fildes[1]描述符。當(dāng)進(jìn)程關(guān)閉前,每個(gè)進(jìn)程需要將沒有關(guān)閉的描述符都進(jìn)行關(guān)閉。

匿名管道具有如下特點(diǎn):

由于這種管道沒有其他同步措施,所以為了不產(chǎn)生混亂,它只能是半雙工的,即數(shù)據(jù)只能向一個(gè)方向流動(dòng)。如果需要雙方互相傳遞數(shù)據(jù),則需要建立兩個(gè)管道;
只能在父子進(jìn)程或兄弟進(jìn)程這些具有親緣關(guān)系的進(jìn)程之間進(jìn)行通信;
匿名管道對(duì)于管道兩端的進(jìn)程而言,就是一個(gè)只存在于內(nèi)存的特殊文件;
一個(gè)進(jìn)程向管道中寫的內(nèi)容被管道另一端的進(jìn)程讀取。寫入的內(nèi)容每次都添加在管道緩沖區(qū)的末尾,并且每次都是從緩沖區(qū)的頭部讀取數(shù)據(jù)。
匿名管道的局限性主要有兩點(diǎn):一是由于管道建立在內(nèi)存中,所以它的容量不可能很大;二是管道所傳送的是無格式字節(jié)流,這就要求使用管道的雙方實(shí)現(xiàn)必須對(duì)傳輸?shù)臄?shù)據(jù)格式進(jìn)行約定。

例子:在父子進(jìn)程之間利用匿名管道通信。

#include
#include
#include
#include
 
#define MAX_LINE 80
 
int main()
{
    int testPipe[2], ret;
    char buf[MAX_LINE + 1];
    const char * testbuf = "主程序發(fā)送的數(shù)據(jù)";
 
    if (pipe(testbuf) == 0) {
        if (fork() == 0) {
            ret = read(testPipe[0], buf, MAX_LINE);
            buf[ret] = 0;
            printf("子程序讀到的數(shù)據(jù)為:%s", buf);
            close(testPipe[0]);
        }else {
            ret = write(testPipe[1], testbuf, strlen(testbuf));
            ret = wait(NULL);
            close(testPipe[1]);
        }
    }
    
    return 0;
}
 

命名管道
由于匿名管道沒有名稱,因此,它只能在一些具有親緣關(guān)系的進(jìn)程之間進(jìn)行通信,這使它在應(yīng)用方面受到極大的限制。

命名管道是在實(shí)際文件系統(tǒng)上實(shí)現(xiàn)的一種通信機(jī)制。由于它是一個(gè)與進(jìn)程沒有“血緣關(guān)系”的、真正且獨(dú)立的文件,所以它可以在任意進(jìn)程之間實(shí)現(xiàn)通信。由于命名管道不支持諸如lseek()等文件定位操作,嚴(yán)格遵守先進(jìn)先出的原則進(jìn)行傳輸數(shù)據(jù),即對(duì)管道的讀總是從開始處返回?cái)?shù)據(jù),對(duì)它的寫總是把數(shù)據(jù)添加到末尾,所以這種管道也叫做FIFO文件。

同樣,由于需要由管道自身來保證通信進(jìn)程間的同步,命名管道也是一個(gè)只能單方向訪問的文件,并且數(shù)據(jù)傳輸方式為FIFO方式。

也就是說,命名管道提供了一個(gè)路徑名與之關(guān)聯(lián),以FIFO的文件形式存在于文件系統(tǒng)中,在文件系統(tǒng)中產(chǎn)生一個(gè)物理文件,其他進(jìn)程只要訪問該文件路徑,就能彼此通過管道通信。在讀數(shù)據(jù)端以只讀方式打開管道文件,在寫數(shù)據(jù)端以只寫方式打開管道文件。

FIFO文件與普通文件的區(qū)別:

普通文件無法實(shí)現(xiàn)字節(jié)流方式管理,而且多進(jìn)程之間訪問共享資源會(huì)造成意想不到的問題;
FIFO文件采用字節(jié)流方式管理,遵循先入先出原則,不涉及共享資源訪問。
操作流程為:mkfifo -> open -> read(write) -> close ->unlink。

到此,相信大家對(duì)“Linux的管道是什么”有了更深的了解,不妨來實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!


分享名稱:Linux的管道是什么
文章地址:http://m.jcarcd.cn/article/ipdsjo.html
主站蜘蛛池模板: 国产白虎不卡在线 | 日本中文字幕网 | 国产一区亚洲 | 91免费版下载 | 欧美日韩电影一级 | 97视频网站 | 黑人巨大跨 | 欧美三极婬片网站 | 欧美一级特 | 日本韩国欧美午夜 | 国产又爽又黄免费 | 日韩在线观看第一页 | 国产大道香蕉大在线 | 日韩在线影院 | 欧美日韩亚洲另 | 国产自产一二三区 | 中文字幕日韩高清 | 国产日韩欧美一区 | 国产精品网友自拍 | 国内揄拍国 | 国产免费高清 | 99热国| 精品国产欧美精品v | 日本成人免费专区 | 乱码一二三入区口 | 国产在香蕉播放 | 欧美日韩第一区 | 欧美性大战 | 无码精品少妇a无码久久 | 成人午夜看免费视频 | 福利导航在线观看 | 91人成亚洲高清 | 国产美女精品一区 | 午夜成人A级片 | 9久热草极品 | 日本伦理片在线看 | 国产美女脱的黄的全 | 国产精品一线 | 国产精品五月天 | 国产日韩欧美二区 | 国产性自|