摘要:本文在闡述電子郵件原理、相關網絡協議和軟件的基礎上,提出一種按照流量計費的電子郵件服務器解決方案,并給出該方案的實現模型。 |
1 前言 電子郵件是Inte.net服務的重要組成部分。隨著Internet技術日新月異的發展,電子郵件以其方便、快速、廉價和可靠的特點越來越贏得人們的喜愛?,F在,電子郵件已經成為學術界、商業界最為流行的一種通信方式,和國外進行學術交流更少不了電子郵件。 在國外,電子郵件服務一般是一次性收取服務費,或者是商業廣告性質的免費服務。但是,在CERNET按照網絡流量計費的大前提下,為公眾提供電子郵件服務時,將不得不考慮流量計費的問題。 本文將從Internet電子郵件原理入手,在闡明相關網絡協議和軟件的基礎上,提供一種按照流量計費的電子郵件服務器解決方案,并給出該方案的實現模型。 2 Internet郵件原理 2.1 Internet電子郵件簡介 為了保證電子郵件系統的正常運行,TCP/IP定義了一組協議,SMTP(簡單郵件傳輸協議)、POP3(郵局協議)和IMAP(Internet消息通道協議)是主要的幾個協議。它們的關系如圖1所示:
圖1 Internet郵件傳送示意圖 圖1顯示了電子郵件從發送到接收的一個單向的典型過程。SMTP和POP3服務器是服務器軟件,它們運行在郵件服務器上。SMTP服務器負責接收待發送的郵件,并發送至目標郵件服務器的SMTP服務器,由該SMTP服務器寫入用戶郵箱。實際上,由于SMTP服務器具有中轉(Relay)功能,它并不區分郵件是來自用戶機(如普通PC)還是其他SMTP服務器。如果用戶想在普通客戶機(沒有SMTP服務器的普通主機)上接收郵件的話,他需要通過POP3協議或IMAP協議從郵件服務器上獲取。不同的是,POP3服務器要求用戶將郵件取回本地的普通客戶機進行維護,而IMAP則可以在服務器上直接維護,例如建立不同的郵件夾等。到目前為止,POP3的使用比IMAP要廣泛的多,下面我們主要介紹SMTP協議和POP3協議。 2.2 SMTP協議 SMTP(Simple Mail Transfer Protocol, RFC 821)是一個用7-bit基本ASCII字符傳送簡單信文的郵件協議。它是一個獨立的用戶級協議,它要求一個可靠的數據通道。在TCP/IP協議中,這個通道是8-bit的TCP數據流,因此SMTP的7-bit字節一律按照最高位為零的8-bit字節進行傳輸。如果要傳送8-bit數據,需要用特殊的調制算法(例如MIME)將其轉為7-bit數據,在接收端再用相反的算法將其復原。 SMTP的一個重要特點是“中轉”(Relay)。一般地,用戶可以選擇任意一臺SMTP服務器(如A)來發送郵件(只要能與該服務器建立傳輸層連接),若該服務器與目標SMTP服務器B可以建立直接連接,則郵件將被直接送至目標服務器B;若不能建立直接連接,該SMTP服務器將向其他所知的SMTP服務器詢問路由,假如有一臺SMTP服務器C可以與目標建立直接連接,或知道通向目標的路由,則郵件被轉至服務器C,由服務器C向目標B轉發。不管是從客戶機到服務器的發送還是服務器間的中轉,SMTP使用同一套指令來進行連接和數據的接收發送,從而使得整個過程清晰簡捷。 Sendmail 是由美國加州大學開發的一個基于UNIX的共享SMTP服務器軟件,它支持多種UNIX的CLONE平臺,如Solaris、Linux等,并且兼容很多其他類型的電子郵件系統,如UUCP等。Sendmail模型如圖2所示。
圖2 Sendmail模型 圖2中,客戶方sender與SMTP服務器Sendmail建立連接,將郵件送交Sendmail服務器;Sendmail按照郵件的不同類型,送交不同的郵件發送程序(稱之為mailer)進行發送,例如SMTP mailer,UUCP mailer等等。Sendmail提供一種Local mailer程序mail.local,對郵件目標地址進行認證,若合法則將郵件寫入用戶的郵箱,否則將郵件退回。 2.3 POP3協議 POP3(Post Office Protocol version 3, RFC 1939)定義了客戶機從郵件服務器上獲取郵件的一個簡單的方法,它通過一組簡單指令和應答實現與用戶的交互操作。例如,用戶通過user指令和pass指令實現身份認證,認證成功后可以通過retr指令收取郵件等。 加州大學針對SMTP服務器Sendmail,開發了一個共享的POP3服務器軟件popper,該軟件具有與Sendmail相同的支持多平臺和多種類型郵件的優點,并且在設計上采用結構清晰的狀態機模型,其模型如圖3所示。
圖3 popper狀態機模型 如圖3,系統初始狀態為AUTH,身份認證通過后進入TRANSACT狀態,系統郵箱被拷貝至一個臨時文件。這一狀態中,用戶可以通過list命令列出郵件頭的信息,通過retr指令將指定郵件取回本地機,通過dele命令將指定郵件標識為刪除,等等。接到quit指令后,進入UPDATE狀態,系統將沒有被標識為刪除的郵件反拷貝回系統郵箱,然后進入HAULT狀態退出。 3 計費郵件服務器要解決的問題 3.1 計費信息獲取 1. 流量。流量即郵件的長度,它是我們計費的基準。因為每一個來件都交由mail.local遞送,所以在mail.local里可以容易地得到每個郵件的長度;另外,用戶取信時與popper連接,popper要對信箱中每個郵件制作一個消息頭(包括郵件的長度,在郵箱中的位置,是否被檢索過等信息),同時也會獲得郵箱的總長度,因此在popper中也可以獲得流量,但程序上的開銷會大一些(例如為了避免重復計費,在每次收信時需要判斷郵件是否被檢索過)。 2. 郵件的來源。目前在我國四大網(教育網CERNET,科學院網CASNET,電子部金橋網CHINAGBN和CHINANET)內,網絡流量是不計費的,因此應當根據郵件源地址是免費區域和非免費區域按照不同的標準計費。這需要獲取郵件的源地址,源地址在mail.local和popper中都可以獲得。此外,對于Internet上一些反動或黃色站點的來信,應當禁止寫到用戶信箱里去。由于這個原因,我們應當在mail.local中就獲得來信地址。 3. 用戶取信的時間和客戶機IP地址。這兩種信息主要用于管理,例如,我們可以通過IP地址為用戶限制可取信的客戶機范圍,從而可保護用戶的郵件不被他人獲取。另外,將這兩條信息記入帳表后可為用戶的查詢提供極大的方便。這兩種信息只能在popper中獲得。 從上面的分析可以看到,我們需要一個基于mail.local和popper的綜合解決方案,才能充分利用已有資源,在開銷盡可能小的前提下獲得以上信息。
3.2 帳戶管理問題 1. 為非UNIX用戶提供郵件服務。每一個UNIX的用戶都有一個郵件帳戶,Sendmail的缺省的帳戶管理也是面向這些用戶的,它需要對UNIX用戶進行身份認證。例如,mail.local獲得了一封給jdx的來信,要使用UNIX系統調用對“jdx”進行認證,如果系統沒有一個叫做jdx的UNIX帳號,將返回空值,來信將被退回。在popper中除了以上步驟外,還要檢查用戶輸入的密碼與系統中密碼是否相同。 這樣的機制不適合對大量郵件用戶的管理。首先,每增加一個郵件用戶就需要建立一個UNIX帳號,用戶所享受的將不僅是電子郵件服務,給用戶權限管理帶來不便;其次,對于大量帳號的快速檢索也成問題。另外,所有的郵箱文件存放在一個目錄下,例如/var/mail或/var/spool/mail下,在文件過多時,系統效率降低,還可能給管理帶來麻煩。 因此,我們需要建立自己的帳戶管理機制。這個機制應當能夠實現: 1) 支持沒有UNIX帳號的普通郵件帳戶; 2) 用戶的郵箱文件應能分類寫入不同的目錄; 3) 能夠對用戶信箱按照用戶名進行快速檢索。 2. 用戶表的管理。用戶表包括的信息有帳號,加密的口令,真實姓名,狀態(正常,欠費,不受歡迎等等)。為了提供快速檢索,用戶表應當是一個排序的表。 用戶表是一個動態的表,每天都可能有新用戶加入,也可能有老用戶注銷。而且,計費郵件服務器要能根據用戶的費用情況自動修改用戶的權限。例如,用戶申請帳號時需要預付一定數量的使用費,此時用戶為正常用戶;一旦使用超過限度(收取了大量郵件),系統將其置為欠費用戶,暫時禁止取信,在用戶補交足夠的費用時,系統恢復其取信權利。因此,用戶表應當及時更新。 為了減少管理難度,提供自我服務,應當向用戶提供隨時修改口令的機制。另外,用戶表應當有一個安全可靠的后備,在用戶表出現故障時能夠及時地修復。 3.3 記帳的問題 用戶每次取信的相關信息,例如時間、地點(IP)、取了多少封信、長度是多少等,都應當記錄下來。作為專用郵件服務器,一般都要為大量的用戶提供服務,假設有20000用戶,每人每天取信一次。這樣,一天大約有兩萬條記錄,這些記錄基本集中在從早上8點到晚上10點的14個小時(3600*14=50,400秒)內,即平均每2.5秒一條記錄。在這樣的情況下,同一時刻處理好幾條記錄的可能性非常大。如果將記錄實時地交給數據庫處理,將加重數據庫負荷,延長響應時間,并增加丟失數據的可能性,嚴重時甚至可能導致系統崩潰。 一個解決辦法是,每次的記錄寫入一個日志文件,每天在數據庫負荷最低的時候,對這個文件進行批處理。 4 計費郵件服務器的實現 4.1 解決方案 針對上面提出的問題,我們可以設計如下解決方案: 1. 將計費郵件系統分為兩個模塊,郵件處理模塊和數據庫計費模塊。郵件處理模塊按照用戶表進行常規的郵件收發和計費日志記錄;數據庫計費模塊讀計費日志、處理帳目、并更新用戶表。兩個模塊通過共享用戶表mail-usr-tab,郵件信息表mailmsgtab,和計費日志實現相互通信。 2. 修改mail.local,插入計費模塊,以獲取來信的源地址,識別郵件的長度及是否國外郵件,并將這些信息寫到一個中間表mailmsgtab里;修改popper,插入計費模塊,在用戶使用popper取郵件時,將該郵件的信息從中間表mailmsgtab中取出來,連同用戶的IP及取信時間一同寫入日志文件,并將mailmsgtab中相應條目清空,以避免對同一封郵件的重復計費。這樣,既獲得了郵件的源地址,又獲得了用戶的本地IP。對于不受歡迎站點的來信,可以在mail.local中將其源地址識別出來之后,退回發送者或者丟棄。對于欠費用戶或不受歡迎的用戶,可以在用戶通過popper獲取郵件時拒絕用戶的請求。 3. 如果直接由popper寫計費日志的話,可能會出現幾個進程同時寫一個文件的情況。雖然用互鎖機制可以避免寫丟失,但在一個進程寫的時候其它幾個進程必須等待,延長了響應時間,降低了系統性能。因此采用一個專門的進程寫計費日志,稱為通信守護進程(cmpd,Communication Monitor Process Daemon)。所有的計費信息由popper使用UDP包發送給它,由它寫入日志。 4. 提供自我服務,開發一個自我服務程序,用戶可以通過遠程登錄啟動該程序的一個進程來修改在用戶表中的密碼,象常規的密碼修改程序一樣,普通用戶首先需要使用舊密碼進行身份認證,管理員可以修改任何用戶的密碼。 4.2 計費郵件服務器實現模型 根據上述解決方案,設計出計費郵件服務器實現模型如下: 圖4 計費郵件服務器實現模型 整個計費郵件系統由sendmail、mail.local、popper、通信守護進程cmpd、計帳程序、密碼修改程序及相關數據構成,其相互關系及工作流程在4.3節中說明,下面介紹主要數據結構。 1) 用戶表mailusrtab char name[17]; /* 用戶名 */ char student_no[15];/* 學號/證號 */ char passwd[17]; /* 加密的密碼 */ char realname[21]; /* 真實姓名 */ int usertype; /* 用戶類型 */ char annotation[31];/* 備注 */ 2) 信件信息表mailmsgtab char name[15]; /* 用戶名 */ int msgnum_f; /* 國外信件數 */ long size_f; /* 國外信件長 */ int msgnum_n; /* 國內信件數 */ long size_n; /* 國內信件長 */ 3) 計費日志mailfee.log char pktype; /* 國內/國外 */ char reserved[6]; /* 保留 */ char user[17]; /* 用戶名 */ char student_no[15];/* 學號 */ struct tm recvdate; /* 取信時間 */ short msgnum; /* 信件數 */ long droplength; /* 信件長 */ char IPaddr[16]; /* 取信的IP */ char checksum; /* 校驗和 */ 4.3 系統的典型工作過程 下面我們用一個實際的例子來看系統的工作過程: 1. 一封寄給studmail@mail.cic. tsinghua.edu.cn的郵件到達郵件服務器mail.cic.tsinghua.edu.cn,SMTP服務器程序sendmail接收該郵件并轉交mail.local程序;mail.local首先判斷該郵件是否從不受歡迎的站點寄來的信,若是則退回;若不是則查詢用戶表,確認本機有此用戶后將郵件寫入名為studmail的系統郵箱,同時將郵件信息寫入郵件信息表mailmsgtab。 2. 在166.111.5.1的用戶studmail在pop3客戶程序中輸入自己的帳號和口令,并與mail.cic.tsinghua.edu.cn的pop3服務器程序popper連接。popper查詢用戶表,如果是正常用戶,由pop_dropcopy將系統郵箱拷貝至臨時郵箱,同時將該用戶在mailmsgtab表中的記錄連同郵件總長度及用戶IP作為UDP包發送給守護進程cmpd,并清空mailmsgtab表中相應記錄。用戶可以通過其他POP3指令從臨時郵箱中收取郵件,刪除郵件等等,結束后由popper將沒有刪除的郵件反拷貝至系統郵箱;如果popper發現該用戶是欠費用戶,則將保存有催款信息的公告郵箱,而不是含有用戶郵件的系統郵箱拷貝至臨時郵箱,其他過程相同,這樣用戶只能看到催款信息,直到其標志恢復為正常用戶。 3. cmpd將接收到的UDP包進行校驗,確認是正常的計費信息后寫入日志文件。 4. 計帳程序在每天的指定時刻(一般為上線較少的深夜) 將日志文件寫入數據庫,同時把用戶在用戶表中修改過的密碼寫入數據庫,最后根據數據庫更新用戶表mailusrtab(包括修改用戶標志,增加新用戶,刪除舊用戶等等)和郵件信息表mailmsgtab(為新用戶增加表項)。 5. 密碼修改程序作為TCP/IP超級服務器inetd的子服務程序,在用戶使用遠程登錄時自動啟動,為用戶提供密碼修改服務,并根據用戶操作更新其在用戶表mailusrtab中的相應表項。 4.4 系統性能分析 影響系統性能的主要問題包括以下幾個方面: 1. cmpd是通過無連接的UDP數據報來接收計費信息的,目的是避免用于連接的時間過長和消耗網絡資源過多。但是,在上線用戶很多的情況下,UDP包的丟包概率有多大?從理論上講,UDP包的丟失最可能是傳輸信道的不可靠性,由于我們的發送方和接收方在同一臺主機上,所以信道是相當可靠的。對此,我們在Sun-ultra1這種不算高檔的工作站上,用一個進程盡可能快地向cmpd發送UDP包3,000個,結果無一遺漏地被接收。在實際應用中,也沒有發現丟包現象。 2. 每封來信都要向郵件信息表mailmsgtab寫信息,每次取信都要從mailmsgtab中讀信息,在多大程度上會影響系統性能?在設計中,mailmsgtab同用戶表mailusrtab一樣采用用戶名為關鍵字排序,并且其記錄具有一一對應關系,因此,用戶信息在mailusrtab和mailmsgtab中的相對位置是相同的。因為mail.local和popper都要檢索mailusrtab表,所以對于mailmsgtab的檢索可以省去,而直接找到正確的記錄位置。在1000個用戶的試運行期間,用戶普遍反映系統較快,和沒有計費的郵件系統沒有差別。 5 結束語 對電子郵件按流量計費是一個符合中國國情的做法,它的實現有助于電子郵件在我國的普及,必將產生良好的社會效益和經濟效益。按照以上的解決方案,我們成功開發了一套計費郵件系統。該系統在清華大學計算機與管理信息中心開放實驗室的Sun Ultra1 170(Solaris2.5)平臺上對1000個用戶進行了四個月的試運行,效果良好。同時在微機Linux環境做了較小規模的測試,也是較為成功的。 參考文獻: 1. J.Postel. Simply Mail Transport Protocol (FRC821). 1982.8 2. J.Myers. Post Office Protocol –version 3 (RFC1939). 1996.3 3. A.S.Tanenbaum. Computer Network (version 3). 1996 4. Eric Allman. Sendmail – Installation and Operation Guide. 1996 |