新聞中心

        EEPW首頁 > 手機與無線通信 > 設計應用 > 一個點到點的郵件系統設計

        一個點到點的郵件系統設計

        作者: 時間:2005-11-24 來源:網絡 收藏

        摘要:簡單介紹在多功能電話上實現點郵件收發系統的技術和過程。在通信方面,系統使用串口通信,通過Modem用電話號碼作為收發者的地址,避免網絡通信中需要IP地址的問題。在架構上,系統分為服務層和客戶層:服務層負責通信鏈路的建立和數據的收發,客戶層負責郵件管理和客戶界面,增加了系統的靈活性。由于Modem的傳輸速率有限,好的通信協議有助于提高郵件的收發速率,因此結合現有串口通信協議的特點,并實現TMP協議。通過該協議,郵件收發系統每秒可以收發2 KB的郵件數據。

        關鍵詞:點到點  串口通信 AT指令

        引 言


          大量嵌入式設備已經進入人們的日常生活和工作中,人們對嵌入式設備的要求越來越高,功能也越來越復雜。筆者與一個嵌入式硬件制造商合作,為其嵌入式電話產品建立了一個軟件系統,包括操作系統、驅動程序和一系列應用軟件。其中點到點郵件收發系統是一個有明顯特色的應用。

          本系統是一個基于串口通信的點到點郵件收發軟件。運行在嵌入式系統上的郵件收發程序通過Modem以撥號方式連上遠端的嵌入式系統,然后進行郵件發送工作。系統結構如圖1所示。
           
                         圖1Tmail系統結構

          從用戶角度看,其發送流程與普通的電子郵件差不多。用戶在編輯好郵件以后,在收信人一欄中填入對方的電話號碼,點擊發送,系統就會把郵件發送給對應電話號碼的遠端用戶處,當然遠端也必須接有同樣的嵌入式系統。

          系統運行在基于ARM的S3C2410芯片嵌入式目標板上[1]。操作系統是定制的嵌入式Linux,圖形界面使用Qt/Embedded支持。

        1 系統的構架

          系統主要由數據傳輸、郵件編碼、郵件管理和用戶界面四部分組成。由于要時刻監視串口的狀態,所以系統要一直處于運行狀態。但由于嵌入式系統的內存資源和計算資源有限,要盡量減少程序運行時帶給整個系統的負載,采用了兩層的結構,分別叫作服務層和用戶層。服務層負責數據傳輸和郵件編碼,用C語言編寫,生成的可執行文件較小,一直處于運行狀態;用戶層負責郵件的管理和用戶界面,用C++配以Qt/Embedded編寫,由于有大量的界面元素,所以其可執行文件較大,只有用戶需要查看和發送郵件時才運行。這樣就可以大大減少占用的資源,使整個系統具有更快的速度。

          用戶層與服務層的通信分兩個方面:一方面,當用戶層運行時通過信號和共享內存實現實時通信;另一方面,當用戶層沒有運行時,用文件暫存收到的郵件,在用戶層運行后,再由它通知用戶。

          當需要發送郵件時,用戶層先把本地郵件拷貝到共享內存中,然后發送信號通知服務層,服務層接收到信號后,把郵件取出、編碼和發送。在發送過程中,為了讓用戶看到發送的進度,服務端把狀態信息放在共享內存中,然后發送信號通知用戶層更新狀態。當接收郵件時,若用戶層沒有運行,則把收到的郵件解碼后暫存到文件中;若用戶層運行著,則服務層通過共享內存和信號不斷把接收進度傳遞給用戶層,使其顯示給用戶,但此時并不會把郵件數據傳給用戶層,因為此時的郵件數據是經過編碼的,等所有數據都接收結束后,服務層才會把郵件解碼成本地郵件,然后再傳送給用戶層保存、顯示。

        2 服務層的設計與實現

        2.1 串口的初始化

          在Linux中,串口的設備文件一般為/dev/ttyS0和/dev/ttyS1,分別表示串口1和串口2。首先要用open命令打開串口,然后根據具體的應用來配置串口,比如設置波特率、校驗方法、數據位、停止位和流控制等。

        2.2 連接的建立和拆除

          連接的建立過程,就如同一般的撥號上網過程。不同的只是,撥打的電話號碼不是ISP的號碼,而是收信人的號碼,因此需要在收信人方建立一個撥號服務器,使它能夠接通外來的連接請求。Linux下的pppd軟件可以實現撥號功能,mgetty可以用作撥號服務器。用pppd和mgetty來建立連接太過奢侈,因為只需建立物理上連通的鏈路,而不需要用PPP協議建立網絡層鏈路[2]。

          本系統是用AT指令來編寫撥號和撥號服務器代碼的。AT指令是一組對Modem的操作指令,其中絕大多數指令都以AT開頭,以/r結尾[3]。用到的AT指令有:

        ① 初始化指令――AT;
        ② 撥號指令――ATDT電話號碼;
        ③ 應答指令――ATA;
        ④ 掛斷指令――+++ATH0。

          工作流程為雙方打開串口并初始化后,都向Modem發送初始化指令(AT),如果返回“OK”,表示成功。成功后,接入方不斷讀取串口(1次/s)等待“RING”字符串。撥號方,通過撥號指令撥打對方電話號碼,并讀取串口等待“CONNECT”字符串。此時,接入方會在串口讀到“RING”,然后向串口發送應答指令(ATA),并讀取串口等待“CONNECT”字符串。此后,如果雙方都讀取到“CONNECT”,表示連接已經建立,可以在此鏈路上傳輸數據。等數據傳輸完成后,撥號方用掛斷指令(+++ATH0)拆除連接。程序的流程如圖2所示。
                  
                        圖2建立和拆除連接流程

        2.3 數據傳輸協議

          現在著名的串口協議主要有XMODEM和ZMODEM。XMODEM協議是一種使用撥號調制解調器的個人計算機通信中廣泛使用的異步文件運輸協議。這種協議以128字節塊的形式傳輸數據,并且每個塊都使用一個校驗和過程來進行錯誤檢測。如果接收方關于一個塊的校驗和與它在發送方的校驗和相同時,接收方就向發送方發送一個認可字節。然而,這種對每個塊都進行認可的策略將導致低性能,特別是具有很長傳播延遲的衛星連接的情況時,問題更加嚴重[4]。ZMODEM協議是XMODEM文件傳輸協議的一種增強形式,它不需要對每個塊都進行認可。事實上,它只是簡單地要求對損壞的塊進行重發。它不僅能傳輸更大的數據,而且錯誤率更小。包含一種名為檢查點重啟的特性,如果通信鏈接在數據傳輸過程中中斷,能從斷點處而不是從開始處恢復傳輸[5]。

          結合XMODEM和ZMODEM優點,根據點到點郵件的特性,設計了一個稱之為TMP(Telephone Mail Protocol)的協議。

        ① 郵件發送方先發送一個郵件信息包(其中包括發送方的電話號碼和郵件長度),然后等待接收方應答。

        ② 接收方接收到郵件信息包后,發送應答包,等待郵件內容包。

        ③ 發送方接收到應答包后,開始發送郵件內容,直到郵件發送完畢或收到重發包。

        ④ 接收方接收郵件內容包,并檢查其檢驗和,如有誤則發送重發包,否則一直接收。

        ⑤ 發送方若收到重發包,則根據重發包內容重發部分郵件;若郵件發送完畢,還未收到重發包,則發送郵件結束確認包,要求接收方確認已正確接收到郵件。

        ⑥ 接收方接收到郵件結束確認包后,發送應答包,表示自己已正確接收到郵件。

        ⑦ 發送方接收到應答包后斷開連接。

        ⑧ 在此過程中,等待都有超時計時,一旦超時就會斷開連接;接收方接收到錯誤的包都會要求重發,而如果發送方接收到錯誤的包則會馬上停止發送,斷開連接。

        ⑨ 包采用變長包,最大長度為128字節,結構為
                
        其中:
        ◇ S為包起始符,取值為0x02,占1字節;
        ◇ E為包結束符,取值為0x03,占1字節;
        ◇ 包號本為占4字節的整型,但在傳輸過程中為了防止與包起始和結束符混淆,把它編成了BCD碼,占8字節;
        ◇ 包類型也編成了BCD碼,占2字節;
        ◇ 檢驗和是以字節為單位,把包號、包類型和數據累加起來,然后再編成BCD碼,占2字節;
        ◇ 數據根據包的類型不同而不同,最多可以有114字節。

          由于包的判斷只是依靠包起始符和結束符,包中的其他字段絕對不能與這兩個字符相同,所以對有些可能產生混淆字符的字段進行了編碼。

        一共有五種類型的數據包:

        ① 郵件內容包。包類型為0x00,數據是編碼的郵件片斷。

        ② 郵件信息包。包類型為0x81,數據是編成BCD碼的發送方電話號碼和郵件長度。

        ③ 郵件結束確認包。包類型為0x82,無數據。

        ④ 應答包。包類型為0x83,無數據。

        ⑤ 重發包。包類型為0x84,數據是編成BCD碼的新包號和重發起始位置。

        2.4 包的發送和接收

          包的發送和接收就是按照包的格式定義讀寫串口。郵件的收發過程就是依照TMP協議收發包的過程。

        2.5郵件的編碼和解碼

          本系統要求發送的郵件是可以帶附件的。在初始化串口時使用的是7位數據,而附件內容可能是二進制數據,這和普通電子郵件碰到的問題一樣,要涉及到對郵件的編碼問題。在設計該系統前,已經實現了普通電子郵件的客戶端軟件,所以就把普通電子郵件的編碼方法應用到這里,也就是點到點郵件也用MIME格式來編碼[6]。

        3 客戶層的設計與實現

        3.1 本地郵件的格式

          本地郵件是指起草的、已發的或收到的存放在各信件箱中的郵件。

          本地郵件可以有兩種存放方式:①按照MIME編碼,把編碼后的郵件放在郵箱中。②按照郵件的組成部分存放在郵箱中。第①種方式的好處是,郵件在發送前和接收后不需要編碼,另外也不需要備份附件文件,可以加快郵件發送和接收速度。但它有兩個最大的缺點,一是因為附件都會編入郵件中,需要大量的存儲空間;二是每次顯示郵件時,都需要把郵件解碼,保存時還要編碼,需要大量的計算資源。這兩點對于資源有限的嵌入式系統來說都是很大的問題。所以這里選擇了第②種方式。
        本地郵件是以文本方式存放在文件中的。本地郵件由發件人、收件人、抄送人、已發送人、時間、標題、正文、回復地址和附件九部分組成。在文件中,除正文外其余八部分都各占1行。其中,抄送人和已發送人可以有多個,之間用分號隔開,附件部分的每個附件都有附件名和實際文件名組成。這兩個文件名間用斜杠隔開,而不同的附件用分號隔開。另外,正文放在郵件的最后,與上面八部分之間有一個空行格開,正文所占行數以正文內容而定。一個本地郵件如下所示:

        Date:2004-08-14
        To:67165848
        From: 67165762
        Cc:67161234;67164321
        Sent:67165848;67161234
        Subject:peer to peer mailer Test
        InReplyTo:67165762
        Attachments:logo.png/20040814085700;face.png/200408145701

        This is a Tmailer Test!
        Hello World!

        3.2 郵件箱文件的組織形式

        一共有四個郵件箱,它們分別是:
        ① 草稿箱(draftbox)――存放起草了但尚未準備發送的郵件。
        ② 發件箱(sendbox)――存放起草完成,可以發送的郵件。
        ③ 已發郵件箱(sentbox)――存放已發送出去的郵件。
        ④ 收件箱(inbox)――存放收到的郵件。

          每個郵件箱由兩個文件組成:郵件內容文件和郵件索引文件。如草稿箱就有草稿郵件內容文件draftbox和草稿郵件索引文件draftbox.index。

          郵件內容文件存放的是該郵件箱中的所有郵件,格式如本地郵件所示。郵件索引文件存放的是每個郵件的基本信息(在顯示郵件列表時要用的信息)及該郵件在內容文件中存放的信息。一個郵件的索引結構如下所示:
        typedef struct {
        chardate[40];// 起草、收到或發出的日期
        charfrom[64];// 發件人或收件人
        charsubject[140];// 標題
        longsize;
        // 郵件的大小(在內容文件中所占的字節數)
        longposInFile;// 在內容文件中的偏移
        intflag;// bit0 = 已讀; bit1 = 是否有附件
        }mail_summery_t;

          由于索引文件較小,當顯示某一郵箱的郵件列表時,可以一次性把整個索引文件內容裝入索引數組中,因此郵件列表的顯示可以不用讀取郵件內容文件,完全取決于索引文件的內容。添加郵件時,在內容文件末尾添加郵件內容,在索引數組中添加一個索引記錄;修改郵件時,不管原郵件在內容文件中的數據,在內容文件末尾添加郵件內容,修改該郵件索引記錄;刪除郵件時,只需刪除索引記錄即可。

          索引文件的使用有兩大好處:一是在顯示郵件列表時不用從較大的內容文件中提取想要顯示的信息;二是方便了郵件的訪問。可以實現郵件的隨機訪問,如果沒有索引文件,在每次修改和刪除郵件時,都需要移動大量的數據。現在,雖然會造成存儲空間的浪費,但這可以提高速度,對于資源有限的嵌入式系統很重要。此外,通過定時判斷郵件內容文件的利用率可以壓縮內容文件的大小,盡量減少空間的浪費。

        3.3 附件的管理

          在郵件中,附件較之郵件其他信息很大,所以郵件管理中附件的管理十分重要。

        ① 用戶在起草郵件并粘貼附件時要把附件文件備份出來,否則如果用戶不小心把附件文件刪除后再發送郵件,就不能發送該附件了。所以要特別開辟出一個文件夾來存放備份的附件。

        ② 用戶收到郵件并郵件解碼后,把其所帶的附件保存到特定的文件夾。

        ③ 用戶在刪除郵件時,也要刪除備份的附件,否則浪費空間。

        ④ 由于附件文件名有可能相同,所以備份附件時要使用惟一文件名。產生惟一文件名的方法是取當前時間字符串加上一個隨機值字符串。

        3.4 郵件的抄送

          本系統也實現了郵件的抄送功能,即一份郵件可以發給多個收信人。用戶層程序把郵件內容及收信人列表(收件人+抄送人-已發送人)傳送給服務層,服務層程序根據收信人列表逐個發送郵件,并記錄發送成功的收信人。在給所有收信人都發送過后(當然不一定每個都成功發送),返回一個已發送成功的收件人列表給客戶層,客戶層把這個列表添加到本地郵件的sent字段中。當郵件的所有收信人,包括收件人和抄送人都收到郵件后,就認為該郵件發送完畢,把它移入已發送郵件箱。

        3.5 界面的設計和實現

        Tmailer主要有六個界面:
        ① 主菜單對話框。Tmailer運行后就是該界面。界面上有六個按鈕,分別用于起草郵件,進入4個郵件箱和退出程序。

        ② 郵件編輯對話框。用于編輯郵件,主要有收件人、抄送人、標題和正文4個編輯框。

        ③ 郵件查看對話框。用于查看收到的郵件,不能編輯。這個對話框上有兩個特殊按鈕,“轉發”按鈕和“回復”按鈕。當點擊“回復”按鈕時,Tmailer先會起草一篇新郵件,然后把當前郵件的InReplyTo填寫到新郵件的收件人欄中,把當前的正文稍作修改填寫到新郵件的正文中,然后就可以編輯和發送該新郵件了。當點擊“轉發”按鈕時,Tmailer也會先起草一篇新郵件,把當前的正文稍作修改填寫到新郵件的正文中,把當前附件粘貼到新郵件中,然后只要填上收件人就可以轉發郵件了。

        ④ 郵件箱對話框。用于顯示郵件列表和管理郵件。4個郵件箱共用該界面,不同的郵箱只是個別按鈕有所不同。當選中郵件按下回車鍵后,程序會根據當前所在的郵件箱選擇用郵件編輯對話框或郵件查看對話框顯示選中郵件。對于有附件的郵件,在每個郵件前都有一個標記標識。在收件箱中,未打開郵件會以粗體顯示,打開后就以正常字體顯示。

        ⑤ 附件編輯對話框:用于編輯(粘貼和刪除)附件,在郵件編輯對話框中點擊“附件“按鈕可以打開該對話框。

        ⑥ 附件查看對話框。用于查看和保存接收郵件的附件。如果查看的附件是圖像文件,Tmailer會通過Qt/Embedded的程序間通信機制把圖像信息傳遞給圖像顯示程序,讓它來顯示圖像。

        結語

          本文介紹了一個在嵌入式系統上點到點的設計和實現,重點講述了如何在計算、存儲資源有限的特殊環境下,來設計點通信軟件;如何運用AT指令操作Modem;對具體的應用如何來有效地設計串口的通信協議和如何對郵件進行合理有效的管理。本系統已經成功地運行在一款多功能電話上,將來通過擴展還可以增強群發、定時發送等功能。

                          參考文獻
        1 Samsung Electronics. S3C2410X 32?Bit Risc Microprocessor User's Manual Revision 1.2, 2003
        2 Robert Hart. PPP Howto. http://www.faqs.org/docs/LinuxHowto/PPPHowto.html, 1997
        3 Michael R. Sweet. Serial Programming Guide for POSIX Operating Systems(5th Edition). http://digilander.libero.it/robang/rubrica/serial.htm,1999
        4 Richard Stevens W. Unix環境高級編程. 北京:機械工業出版社, 2000
        5 Matt Welsh. Linux權威指南. 第3版. 北京:中國電力出版社, 2000
        金震江:碩士研究生,主要研究方向為嵌入式系統。呂強:教授,主要研究方向為計算機操作系統、分布式計算、計算語言學等。褚亞銘:碩士研究生,主要研究方向為嵌入式操作系統。楊季文:教授,主要研究方向為計算機中文信息處理技術、計算機操作系統。

        c++相關文章:c++教程




        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 南陵县| 米脂县| 赣榆县| 玛多县| 屯昌县| 古丈县| 清新县| 莱阳市| 库尔勒市| 安吉县| 阜康市| 青冈县| 柳州市| 永登县| 乌鲁木齐市| 攀枝花市| 辉南县| 临朐县| 赞皇县| 和硕县| 千阳县| 长子县| 南岸区| 永嘉县| 博湖县| 汉寿县| 开鲁县| 大关县| 荆州市| 武邑县| 修文县| 原平市| 上饶县| 罗源县| 当雄县| 溧水县| 沛县| 保康县| 冷水江市| 台湾省| 青海省|