一个点到点的邮件系统设计
扫描二维码
随时随地手机看文章
摘要:简单介绍在多功能电话上实现一个点到点邮件收发系统的技术和过程。在通信方面,系统使用串口通信,通过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
金震江:硕士研究生,主要研究方向为嵌入式系统。吕强:教授,主要研究方向为计算机操作系统、分布式计算、计算语言学等。褚亚铭:硕士研究生,主要研究方向为嵌入式操作系统。杨季文:教授,主要研究方向为计算机中文信息处理技术、计算机操作系统。