重新審視程序間的通訊(一)

2021-07-12 06:12:13 字數 4075 閱讀 4880

最近幹活的時候又被linux管道和訊息佇列搞的一臉懵逼。當初自己走馬觀花似的學習以為內容很簡單,結果留下了大坑,借來unix網路程式設計來補補,重新審視這兩個部分,並且引以為戒!!!

首先看管道

#includeint pipe(int fd[2]);
返回:成功為0,出錯為1,兩個檔案描述符fd[0]用來讀,fd[1]用來寫

靈魂作圖

單程序管道

剛fork後

父程序關閉管道讀出端,子程序關閉管道寫入端,在父子程序間提供乙個單向資料流

管道只能用於父子程序或者兄弟程序間通訊,也就是說管道只能用於具有親緣關係的程序間通訊

管道的緩衝區大小是受限制的。管道所傳輸的是無格式的位元組流。這就需要管道輸入方和輸出方事先約定好資料格式

有名管道可用於沒有親緣關係的程序間通訊(name pipe或者叫fifo)

#include#includeint mkinfo(const char *pathname, mode_t mode);//pathname為建立有名管道的全路徑名,mode為建立有名管道的模式

返回:若成功則0,不成功則-1

實現分析

//管道緩衝區個數

#define pipe_buffers (16)

//管道快取區物件結構

struct pipe_buffer ;

//管道資訊結構

struct pipe_inode_info ;

//管道讀操作函式

static ssize_t

pipe_readv(struct file *filp, const struct iovec *_iov,

unsigned long nr_segs, loff_t *ppos)

//更新管道的offset和len欄位

ret += chars;

buf->offset += chars;

buf->len -= chars;

//若現在的快取區的資料長度為0

if (!buf->len)

total_len -= chars; //更新讀的總長度

if (!total_len) //該讀的已讀完成

break; /* common path: read succeeded */

} if (bufs) /* more to do? */

continue;

//若bufs為0,說明所有管道為null,此時進行一下操作

if (!pipe_writers(*inode)) //是否有寫操作正在進行

break;

if (!pipe_waiting_writers(*inode))

} if (signal_pending(current))

if (do_wakeup)

pipe_wait(inode);

} up(pipe_sem(*inode));

/* signal writers asynchronously that there is more room. */

if (do_wakeup)

if (ret > 0)

file_accessed(filp); //更新檔案結構的atime物件

return ret;

}static ssize_t

pipe_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)

; return pipe_readv(filp, &iov, 1, ppos);

}/* drop the inode semaphore and wait for a pipe event, atomically */

void pipe_wait(struct inode * inode)

static ssize_t

pipe_writev(struct file *filp, const struct iovec *_iov,

unsigned long nr_segs, loff_t *ppos)

/* we try to merge small writes */

//若有待讀資料的緩衝區,而且寫入的資料長度小於page_size

if (info->nrbufs && total_len < page_size)

}// 若全部可寫(可讀緩衝區數為0),

// 或寫入資料長度大於管道緩衝區的長度單位(page_size)

for (;;)

//獲取讀緩衝區數

bufs = info->nrbufs;

if (bufs < pipe_buffers)

info->tmp_page = page;

}/* always wakeup, even if the copy fails. otherwise

* we lock up (o_nonblock-)readers that sleep due to

* syscall merging.

* fixme! is this really true?

*/do_wakeup = 1;

chars = page_size;

if (chars > total_len)

chars = total_len;

//寫chars位元組到緩衝區中

error = pipe_iov_copy_from_user(kmap(page), iov, chars);

kunmap(page);

if (unlikely(error))

ret += chars;

/* insert it into the buffer array */

/更新nrbufs,和len欄位。

buf->page = page;

buf->ops = &anon_pipe_buf_ops;

buf->offset = 0;

buf->len = chars;

info->nrbufs = ++bufs;

info->tmp_page = null;

//若沒有寫完繼續寫入剩下的資料

total_len -= chars;

if (!total_len)

break;

}//還有可寫緩衝區,繼續寫

if (bufs < pipe_buffers)

continue;

//若設定非阻塞,

//若沒有寫入任何的資料ret=0,此時返回錯誤

//若已經寫完了資料,結束寫操作。

if (filp->f_flags & o_nonblock)

if (signal_pending(current))

if (do_wakeup)

pipe_waiting_writers(*inode)++;

pipe_wait(inode);

pipe_waiting_writers(*inode)--;

}out:

up(pipe_sem(*inode));

if (do_wakeup)

if (ret > 0)

inode_update_time(inode, 1); /* mtime and ctime */

return ret;

}

ps:管道是作為一組vfs物件來實現的,因此沒有對應的磁碟映像。所以管道的安裝和實現都是vfs類似,此處不進行**

程序間通訊(一)

為什麼程序間要通訊?1 資料傳輸 2 資源共享 3 通知事件 4 程序控制 程序間通訊方式 管道通訊 共享記憶體 訊息佇列 訊號通訊 一 管道通訊 管道是單向的 先進先出的,它把乙個程序的輸出和另乙個程序的輸入連線在一起。乙個程序 寫程序 在管道尾部寫入資料,另乙個程序 讀程序 從管道的頭部讀出資料...

程序間通訊(一)

半雙工管道 fifo 全雙工管道 命名全雙工管道 訊息佇列 訊號量 共享記憶體 套接字 多機其它為單機 管道 包括無名管道 命名管道 訊息佇列 訊號量共享儲存 scoket streams 等。其中,scoket和stream支援不同主機上的兩個程序ipc。一 管道 管道,通常指無名管道,是unix...

程序間通訊 一)

測試 例子 從鍵盤讀取資料,寫入管道,讀取管道,寫到螢幕 include include include include intmain void memset buf,0x00 sizeof buf read from pipeif len read fds 0 buf,100 1 write t...