管道基礎

##管道基礎
#通信分類:只寫單工管道、只讀單工管道、半雙工管道(單向讀寫)、全雙工管道(兩個半雙工管道拼接)
    類型        創建/打開    關閉            讀    寫
    單工        popen()        pclose()        read()    write()
    半雙工        pipe()/open()    close()            read()    write()
    FIFO半雙工    mkfifo()/open()    close()/unlink()    read()    write()
    全雙工        socketpair()    close()            read()    write()
管道通常用於進程間通信,可以用KFC買東西來比喻,通過man 7 pipe來查看管道在redhat中的官方解釋。

#管道的分類
    @匿名管道
        特點:必須是親緣進程之間
        案例:
            ps_self        \\打印自身的父子進程信息
            ps_other    \\執行參數中的命令,並且打印參數中的命令相關的父子進程
        分類:
            *單工管道
                操作:    管道        文件
                打開    popen()        fopen()
                關閉    pclose()    pclose()
                
            打開管道:FILE* popen(const char* command,const char* open_mode);
                command:命令行字符串
                open_mode:只讀"r";只寫"w"
                返回值:文件描述符    NULL(打開失敗)
            讀寫:
                size_t fread(void* buffer,size_t size,size_t count,FILE* stream)
                    buffer:用於接收數據的內存地址
                    size:讀取每個數據項的字節數
                    count:數據項個數
                    stream:輸入流
                    返回值:出錯(>count)、整數(實際讀取的數據項個數)
                size_t fwrite(const void* buffer,size_t size,size_t count,FILE* stream)
                    buffer:寫入數據的內存地址
                    size:寫入數據項的字節數
                    count:寫入數據項的個數
                    stream:目標文件指針
                    返回值:出錯(>count)、正數(實際寫入的數據項個數)
            關閉管道:int pclose(FILE* stream);
                stream:文件描述符
                返回值:失敗(-1)、成功(0)
            本質:
                a.啓動shell和命令兩個進程,從命令進程中讀/寫文件流
                b.解決exec和system無法返回輸出數據問題
            特點:
                a.方便使用系統自帶功能,並且可以執行比較複雜shell
                b.默認啓動兩個進程,效率較低

            *半雙工管道
                操作:    
                    創建管道:int pipe(int filedes[2])
                        filedes[0]    讀
                        filedes[1]    寫
                        返回值:失敗(-1)、成功(0)
                    讀寫
                        ssize_t write(int fd,const void* buf,size_t nbyte)
                        fd:文件描述符
                        buf:寫入數據的內存單元
                        nbyte:寫入文件指定的字節數
                        返回值:出錯(-1)、正數(寫入的字節數)
                        ssize_t read(int fd,void* buf,size_t count)
                        fd:文件描述符
                        buf:讀入數據的內存單元
                        返回值:出錯(-1)、0(無數據)、正數(讀取的字節數)
                    控制:如果管道是空的,read()默認是阻塞
                        int fcntl(int fd,int cmd,long arg)
                        fd:文件描述符
                        cmd:F_GETFL(獲取文件描述符狀態)、F_SETFL(設置文件描述符狀態)、……
                        arg:O_NONBLOCK(非阻塞)、O_BLOCK(阻塞)、……

                        fcnt(filedes,F_SETFL,O_NONBLOCK);    \\把文件描述符改爲非阻塞的。
                        
                    關閉管道:close(filedes)    
                本質:文件描述符[文件流是文件描述符之上的封裝。文件流通過增加緩衝區減少讀寫系統調用次數來提高讀寫效率。在進程的用戶空間封裝的FILE結構,以提高可移植性和效率]
            *複製管道
                定義:Linux內核使用三個關聯的數據結構,表示打開的文件。【描述符表,文件表,v-node表】內核爲每個進程創建的文件文件描述符。
        分類        文件描述符    文件號
        標準輸入    STDIN_FILENO    0
        標準輸出    STDOUT_FILENO    1
        標準出錯信息    STDERR_FILENO    2
                
                int dup(oldfd)    \\返回值:-1(失敗)、其他(新的文件描述符)
                int dup2(int oldfd,int newfd)    \\返回值:-1(失敗)、其他(最小及尚未使用的文件描述符)
    
    @【半雙工】FIFO管道/命名管道
        特點:可以是非親緣進程之間;讀寫必須同時執行,否則阻塞。
        案例:FIFO工具箱
        操作:
            創建命名管道:int mkfifo(pathname,mode)【古老方式:int mknod(const char *filename,mode_t mode | S_IFIFO,(dev_t)0);】
                    pathname:文件路徑【文件必須不存在】
                    mode:模式
                    返回值:0(成功)、非零(失敗)
            打開FIFO文件:int open(const char* path,int mode)
                    pathname:文件路徑
                    mode:模式【O_RDONLY(阻塞只讀)、O_RDONLY|O_NONBLOCK(非阻塞只讀)、O_WRONLY(阻塞只寫)、O_WRONLY|O_NONBLOCK(非阻塞只寫)】
                    返回值:-1(失敗)、其他(文件描述符)


                








發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章