日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

系统程序员成长计划-管道过滤器(Pipe-And-Filter)模式

發布時間:2024/3/12 windows 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 系统程序员成长计划-管道过滤器(Pipe-And-Filter)模式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

分享一下我老師大神的人工智能教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

系統程序員成長計劃-文本處理(三)Sunday, June 28th, 2009?|?Author: admin?????|? Edit ????

?

轉載時請注明出處和作者聯系方式
文章出處:http://www.limodev.cn/blog
作者聯系方式:李先靜 <xianjimli at hotmail dot com>

系統程序員成長計劃-文本處理(三)

管道過濾器(Pipe-And-Filter)模式

按照《POSA(面向模式的軟件架構)》里的說法,管道過濾器(Pipe-And-Filter)應該屬于架構模式,因為它通常決定了一個系統的基本架構。管道過濾器和生產流水線類似,在生產流水線上,原材料在流水線上經一道一道的工序,最后形成某種有用的產品。在管道過濾器中,數據經過一個一個的過濾器,最后得到需要的數據。

o 基本的管道過濾器:

管道負責數據的傳遞,它把原始數據傳遞給第一個過濾器,把一個過濾器的輸出傳遞給下一個過濾器,作為下一個過濾器的輸入,重復這個過程直到處理結束。要注意的是,管道只是對數據傳輸的抽象,它可能是管道,也可能是其它通信方式,甚至什么都沒有(所有過濾器都在原始數據基礎上進行處理)。

過濾器負責數據的處理,過濾器可以有多個,每個過濾器對數據做特定的處理,它們之間沒有依賴關系,一個過濾器不必知道其它過濾器的存在。這種松耦合的設計,使得過濾器只需要實現單一的功能,從而降低了系統的復雜度,也使得過濾器之間依賴最小,從而以更加靈活的組合來實現新的功能。

編譯器就是基于管道過濾器模式設計的:

輸入:源程序
預處理:負責宏展開和去掉注釋等工作。
編譯:進行詞法分析、語法分析、語義分析、代碼優化和代碼產生。
匯編:負責把匯編代碼轉換成機器指令,生成目標文件。
鏈接:負責把多個目標文件、靜態庫和共享庫鏈接成可執行文件/共享庫。
輸出:可執行文件/共享庫。

o 復合過濾器

過濾器可以由多個其它過濾器組合起來的,比如上面的“編譯”過程可以認為是一個復合過濾器:

輸入:預處理之后的源代碼。
詞法分析:負責將源程序分解成一個一個的token,這些token是組成源程序的基本單元。
語法分析:把詞法分析得到的token解析成語法樹。
語義分析:對語法樹進行類型檢查等語義分析。
代碼優化:對語法樹進行重組和修改,以優化代碼的速度和大小。
代碼產生:根據語法樹產生匯編代碼。
輸出:匯編代碼。

o 支持多個輸入的過濾器

過濾器可以有多個輸入。比如上面“鏈接”,它接收多個輸入:

“鏈接”過濾器能接收多個數據源,如目標文件、靜態庫和共享庫。

o 具有多個輸出的過濾器

過濾器可以有多個輸出。如多媒體播放器的解碼過程:

輸入:AVI文件,包括音頻和視頻數據。
分離器:把音頻和視頻數據分離成兩個流,音頻數據傳遞給音頻解碼器,視頻數據傳遞給視頻解碼器。
音頻解碼器:把壓縮的音頻數據解碼成原始的音頻數據。
視頻解碼器:把壓縮的視頻數據解碼成原始的圖像數據。
輸出:音頻數據傳遞給聲卡,圖像數據傳遞給顯示器。

管道過濾器是最貼近程序員生活的模式,也是Unix-like系統的基本設計理念之一。作為Linux下的程序員,我們天天都使用這個模式。比如:

o刪除當前目錄及子目錄下的目標文件。
find -name /*.o|xargs rm –f
? find是過濾器:它找出所有目標文件,它不需要關心查找文件的目的。
? rm是過濾器:它刪除找到目標文件,rm不需要關心文件名是如何得來的。

o 查看某個進程的棧的大小
grep stack /proc/2976/maps|sed -e “s/-/ /”|awk ‘{print strtonum(”0x”$2)-strtonum(”0x”$1)}’

/proc/2976/maps是進程2976內存映射表。內容可能如下:

00110000-00111000 r-xp 00110000 00:00 0????????? [vdso]
00111000-0011b000 r-xp 00000000 08:01 154857???? /lib/libnss_files-2.8.so
0011b000-0011c000 r--p 0000a000 08:01 154857???? /lib/libnss_files-2.8.so
0011c000-0011d000 rw-p 0000b000 08:01 154857???? /lib/libnss_files-2.8.so
00907000-00923000 r-xp 00000000 08:01 157280???? /lib/ld-2.8.so
00923000-00924000 r--p 0001c000 08:01 157280???? /lib/ld-2.8.so
00924000-00925000 rw-p 0001d000 08:01 157280???? /lib/ld-2.8.so
00927000-00a8a000 r-xp 00000000 08:01 157281???? /lib/libc-2.8.so
00a8a000-00a8c000 r--p 00163000 08:01 157281???? /lib/libc-2.8.so
00a8c000-00a8d000 rw-p 00165000 08:01 157281???? /lib/libc-2.8.so
00a8d000-00a90000 rw-p 00a8d000 00:00 0
00abd000-00ac0000 r-xp 00000000 08:01 157284???? /lib/libdl-2.8.so
00ac0000-00ac1000 r--p 00002000 08:01 157284???? /lib/libdl-2.8.so
00ac1000-00ac2000 rw-p 00003000 08:01 157284???? /lib/libdl-2.8.so
0383f000-03855000 r-xp 00000000 08:01 157307???? /lib/libtinfo.so.5.6
03855000-03858000 rw-p 00015000 08:01 157307???? /lib/libtinfo.so.5.6
08047000-080fa000 r-xp 00000000 08:01 1180910??? /bin/bash
080fa000-080ff000 rw-p 000b3000 08:01 1180910??? /bin/bash
080ff000-08104000 rw-p 080ff000 00:00 0
088bd000-088ff000 rw-p 088bd000 00:00 0????????? [heap]
b7bfb000-b7bfd000 rw-p b7bfb000 00:00 0
b7bfd000-b7c04000 r--s 00000000 08:01 237138???? /usr/lib/gconv/gconv-modules.cache
b7c04000-b7d1e000 r--p 047d3000 08:01 237437???? /usr/lib/locale/locale-archive
b7d1e000-b7d5e000 r--p 0236e000 08:01 237437???? /usr/lib/locale/locale-archive
b7d5e000-b7f5e000 r--p 00000000 08:01 237437???? /usr/lib/locale/locale-archive
b7f5e000-b7f60000 rw-p b7f5e000 00:00 0
bfe5e000-bfe73000 rw-p bffeb000 00:00 0????????? [stack]

grep是過濾器:它從文件/proc/2976/maps里找到下面這行數據。

bfe5e000-bfe73000 rw-p bffeb000 00:00 0????????? [stack]

sed是過濾器:它把‘-’替換成‘ ’,數據變成下面的內容。
bfe5e000 bfe73000 rw-p bffeb000 00:00 0????????? [stack]

awk是過濾器:它計算0xbfe73000和0x bfe5e000差值,并打印出來。

下面我們來看看,管道過濾器在程序里的實現方式。這里我們以TinyMail為例,TinyMail是一款針對移動設備定制的郵件客戶端軟件。它使用camel-lite完成郵件內容解析和傳輸。Camel-lite對郵件內容的處理基本上基于管道過濾器模式的。

CamelMimeFilter是過濾器接口,所有過濾器都要實現它要求的接口函數:

struct _CamelMimeFilterClass {
??? CamelObjectClass parent_class;

??? void (*filter)(CamelMimeFilter *f,
?????????????? char *in, size_t len, size_t prespace,
?????????????? char **out, size_t *outlen, size_t *outprespace);
??? void (*complete)(CamelMimeFilter *f,
???????????? char *in, size_t len, size_t prespace,
???????????? char **out, size_t *outlen, size_t *outprespace);
??? void (*reset)(CamelMimeFilter *f);
};

CamelMimeFilterClass是從CamelObjectClass繼承過來的。這里的接口定義和我們前面所講的接口定義有些差別,但原理上都是一樣,通過函數指針來抽象具體的功能。這里要求實現三個接口函數:

filter:過濾器的處理函數。
complete:過濾器的處理函數。與filter不同的是,調用complete之后不能調其它filter。
reset:重置當前filter的狀態。

Camel實現了很多Filter,其中CamelMimeFilterBasic實現了郵件基本的編碼和解析功能。它的filter函數實現如下:

static void
filter(CamelMimeFilter *mf, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace)
{
??? CamelMimeFilterBasic *f = (CamelMimeFilterBasic *)mf;
??? size_t newlen;

??? switch(f->type) {
??? case CAMEL_MIME_FILTER_BASIC_BASE64_ENC:
??????? /* wont go to more than 2x size (overly conservative) */
??????? camel_mime_filter_set_size(mf, len*2+6, FALSE);
??????? newlen = g_base64_encode_step((const guchar *) in, len, TRUE, mf->outbuf, &f->state, &f->save);
??????? g_assert(newlen <= len*2+6);
??????? break;
??? case CAMEL_MIME_FILTER_BASIC_QP_ENC:
??????? /* *4 is overly conservative, but will do */
??????? camel_mime_filter_set_size(mf, len*4+4, FALSE);
??????? newlen = camel_quoted_encode_step((unsigned char *) in, len, (unsigned char *) mf->outbuf, &f->state, (gint *) &f->sa
ve);
??????? g_assert(newlen <= len*4+4);
??????? break;
??? case CAMEL_MIME_FILTER_BASIC_UU_ENC:
??????? /* won't go to more than 2 * (x + 2) + 62 */
??????? camel_mime_filter_set_size (mf, (len + 2) * 2 + 62, FALSE);
??????? newlen = camel_uuencode_step ((unsigned char *) in, len, (unsigned char *) mf->outbuf, f->uubuf, &f->state, (guint32
*) &f->save);
??????? g_assert (newlen <= (len + 2) * 2 + 62);
??????? break;
??? case CAMEL_MIME_FILTER_BASIC_BASE64_DEC:
??????? /* output can't possibly exceed the input size */
??????? camel_mime_filter_set_size(mf, len+3, FALSE);
??????? newlen = g_base64_decode_step(in, len, (guchar *) mf->outbuf, &f->state, (guint *) &f->save);
??????? g_assert(newlen <= len+3);
??????? break;
??? case CAMEL_MIME_FILTER_BASIC_QP_DEC:
??????? /* output can't possibly exceed the input size */
??????? camel_mime_filter_set_size(mf, len + 2, FALSE);
??????? newlen = camel_quoted_decode_step((unsigned char *) in, len, (unsigned char *) mf->outbuf, &f->state, (gint *) &f->sa
ve);
??????? g_assert(newlen <= len + 2);
??????? break;
??? case CAMEL_MIME_FILTER_BASIC_UU_DEC:
??????? if (!(f->state & CAMEL_UUDECODE_STATE_BEGIN)) {
??????????? register char *inptr, *inend;
??????????? size_t left;

??????????? inptr = in;
??????????? inend = inptr + len;

??????????? while (inptr < inend) {
??????????????? left = inend - inptr;
??????????????? if (left < 6) {
??????????????????? if (!strncmp (inptr, "begin ", left))
??????????????????????? camel_mime_filter_backup (mf, inptr, left);
??????????????????? break;
??????????????? } else if (!strncmp (inptr, "begin ", 6)) {
??????????????????? for (in = inptr; inptr < inend && *inptr != '/n'; inptr++);
??????????????????? if (inptr < inend) {
??????????????????????? inptr++;
??????????????????????? f->state |= CAMEL_UUDECODE_STATE_BEGIN;
??????????????????????? /* we can start uudecoding... */
??????????????????????? in = inptr;
??????????????????????? len = inend - in;
??????????????????? } else {
??????????????????????? camel_mime_filter_backup (mf, in, left);
??????????????????? }
??????????????????? break;
??????????????? }

??????????????? /* go to the next line */
??????????????? for ( ; inptr < inend && *inptr != '/n'; inptr++);

??????????????? if (inptr < inend)
??????????????????? inptr++;
??????????? }
??????? }

??????? if ((f->state & CAMEL_UUDECODE_STATE_BEGIN) && !(f->state & CAMEL_UUDECODE_STATE_END)) {
??????????? /* "begin <mode> <filename>/n" has been found, so we can now start decoding */
??????????? camel_mime_filter_set_size (mf, len + 3, FALSE);
??????????? newlen = camel_uudecode_step ((unsigned char *) in, len, (unsigned char *) mf->outbuf, &f->state, (guint32 *) &f-
>save);
??????? } else {
??????????? newlen = 0;
??????? }
??????? break;
??? default:
??????? g_warning ("unknown type %u in CamelMimeFilterBasic", f->type);
??????? goto donothing;
??? }

??? *out = mf->outbuf;
??? *outlen = newlen;
??? *outprespace = mf->outpre;

??? return;
donothing:
??? *out = in;
??? *outlen = len;
??? *outprespace = prespace;
}

這個過濾器實現了下面三種編碼方式的編碼和解碼:
1.?UU(Unix-to-Unix encoding):
2.?Base64
3.?QP(Quote-Printable)

Camel還提供了其它一些過濾器,如:
CamelMimeFilterGZip:壓縮和解壓
CamelMimeFilterHTML:去掉HTML Tag。
CamelMimeFilterCRLF:使用/r/n作為換行符。
CamelMimeFilterToHTML:加上HTML Tag。
CamelMimeFilterCharset:字符集轉換。

所有的過濾器由CamelStreamFilter來組合,CamelStreamFilter提供了下面兩個函數:

增加過濾器:
int camel_stream_filter_add (CamelStreamFilter *stream, CamelMimeFilter *filter);

移除過濾器:
void camel_stream_filter_remove (CamelStreamFilter *stream, int id);

CamelStreamFilter實現了CamelStream接口,這里應用了前面所講的裝飾模式,它不改變CamelStream的接口,但給CamelStream加上了數據轉換功能。它的創建函數如下:

CamelStreamFilter????? *camel_stream_filter_new_with_stream (CamelStream *stream);

傳入一個CamelStream對象,然后對這個對象進行裝飾。在讀寫數據時,調用相應的Filter,下面是寫函數的實現:

do_read (CamelStream *stream, char *buffer, size_t n)
{
??? CamelStreamFilter *filter = (CamelStreamFilter *)stream;
??? struct _CamelStreamFilterPrivate *p = _PRIVATE(filter);
??? ssize_t size;
??? struct _filter *f;

??? p->last_was_read = TRUE;

??? g_check(p->realbuffer);

??? if (p->filteredlen<=0) {
??????? size_t presize = READ_PAD;

??????? size = camel_stream_read(filter->source, p->buffer, READ_SIZE);
??????? if (size <= 0) {
??????????? /* this is somewhat untested */
??????????? if (camel_stream_eos(filter->source)) {
??????????????? f = p->filters;
??????????????? p->filtered = p->buffer;
??????????????? p->filteredlen = 0;
??????????????? while (f) {
??????????????????? camel_mime_filter_complete(f->filter, p->filtered, p->filteredlen,
?????????????????????????????????? presize, &p->filtered, &p->filteredlen, &presize);
??????????????????? g_check(p->realbuffer);
??????????????????? f = f->next;
??????????????? }
??????????????? size = p->filteredlen;
??????????????? p->flushed = TRUE;
??????????? }
??????????? if (size <= 0)
??????????????? return size;
??????? } else {
??????????? f = p->filters;
??????????? p->filtered = p->buffer;
??????????? p->filteredlen = size;
??????????? d(printf ("/n/nOriginal content (%s): '", ((CamelObject *)filter->source)->klass->name));
??????????? d(fwrite(p->filtered, sizeof(char), p->filteredlen, stdout));
??????????? d(printf("'/n"));

??????????? while (f) {
??????????????? camel_mime_filter_filter(f->filter, p->filtered, p->filteredlen, presize,
???????????????????????????? &p->filtered, &p->filteredlen, &presize);
??????????????? g_check(p->realbuffer);

??????????????? d(printf ("Filtered content (%s): '", ((CamelObject *)f->filter)->klass->name));
??????????????? d(fwrite(p->filtered, sizeof(char), p->filteredlen, stdout));
??????????????? d(printf("'/n"));

??????????????? f = f->next;
??????????? }
??????? }
??? }

??? size = MIN(n, p->filteredlen);
??? memcpy(buffer, p->filtered, size);
??? p->filteredlen -= size;
??? p->filtered += size;

??? g_check(p->realbuffer);

??? return size;
}

這里先調用camel_stream_read讀取數據,然后依次調用fitler對數據進行處理,最后把數據返回給調用者。do_write的過程類似,CamelStreamFilter對編碼和解碼都支持,而使用者不用關心。

管道過濾器模式應用相當廣泛,它不限于文本數據處理,任何以數據處理為中心的系統,都可以用管道過濾器模式作為基本架構。

???????????

給我老師的人工智能教程打call!http://blog.csdn.net/jiangjunshow

總結

以上是生活随笔為你收集整理的系统程序员成长计划-管道过滤器(Pipe-And-Filter)模式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。