随着网络嵌入式系统应用的普及,嵌入式系统之间的通信成为工程师关注的焦点之一。除了API或HTTP协议等传统方式外,电子邮件也可以用来进行数据通信,本文描述了一个用于接收信息的小型SMTP服务器以及发送回函的客户程序来说明电子邮件通信方式的应用。
通过电子邮件来与网络嵌入式系统通信有如下优点:(1) 用户接口是日常使用的标准电子邮件客户程序,对技术要求较低;(2) 有现成的协议用于从各种设备(桌面电脑、手持设备及网络电话)发送电子邮件并在因特网上传输;(3) 只需稍加处理,便可对嵌入式设备上回复的电子邮件以HTML格式进行编码,使数据的表现形式更为丰富和易读;(4) 电子邮件客户程序有自己的存档日志,便于进行数据归档备份。
邮件系统的组成
在用因特网发送邮件时,我们使用邮件用户代理(MUA)与本地的邮件传输代理(MTA)进行通信,后者则将电子邮件传送给目标MTA。目标MTA通过一个本地投递服务器(如POP3)将电子邮件传送给接收MUA,如图1所示。
客户与MTA间传送电子邮件的协议称为简单邮件传输协议(SMTP),它的具体条款可在RFC-821中找到。目的MTA接收到邮件,该邮件暂存在接收系统上,邮件接收者可通过POP3将之收集下来(邮局协议)。通过邮局协议可避免在每个需要接收邮件的节点上建立一个SMTP服务器。
协议会话示例
SMTP是一种其于ASCII的简单协议,可通过标准的远程登录客户程序执行。MTA寄存在端口25上,程序1是一段与称为Sendmail(红色显示部分为用户输入)标准MTA的互动会话示例。
通过远程登录打开一个Socket会话后,先通过HELO指令表明身份,然后再通过MMAIL FROM指令告知MTA邮件从何而来,并通过RCPT TO指令表明邮件去向何处。最后,发出DATA指令指示MTA以下文本内容是电子邮件的正文。在正文中输入内容后,通过一个简单的“.”来结束邮件,这个符号独占一行。这时MTA便准备将电子邮件发送给指定姓名的接收者。
这个示例所用功能极少,但作为例子已经足够了。它表明MTA只是一个特殊的命令解释器。当所有的命令都向MTA发出后,会返回一个数字响应代码,以便知道是否执行成功。此外还有多种协议了采用这种模式,包括POP3和网络新闻传输协议(NNTP)。
简单SMTP服务器和客户实现
以下是一个适用于嵌入式系统的简单实现。这个实现的目的是在SMTP传输系统中开发一个命令-响应协议。服务器接收一个电子邮件,然后对它进行语法分析,找出其中的指令(这种情况下,这个指令位于电子邮件的标题栏中)。如果指令合法,就调用一个处理程序产生电子邮件的响应,该响应传送到客户实现上,然后传输回去给用户。整个系统如图2所示。
嵌入式SMTP服务器的组件和客户与图1所示的传统图形有所不同。客户MUA配置了一个SMTP网关(发出邮件服务器)作为嵌入式器件的地址(由于服务器既充当MTU又充当自动MUA)。嵌入式客户采用SMTP GATEWAY #define(程序1)来定义从何处发送响应电子邮件。
实现过程
主要功能(可从获得完整的源代码)提供了基本的服务器插座设置以便邮件连接。将插座绑定到端口25,即SMTP服务的标准端口。然后执行一个循环等待连接,当有客户连接时调用MailReceive函数。为了简化实现,一次只处理一个连接。
MailReceive函数实现SMTP协议的服务器端功能,如实例程序2所示。MailReceive函数中的第一步是将初始化标志发送给客户程序,然后等待其响应。接着顺序等待接收“MAIL
FROM”、“RCPT TO”及“DATA”命令,并存储结果及发送相应的返回码。
接收邮件正文的操作十分简单,只需将收到的字符缓存起来,直到接收到一个特殊的字符序列为止。客户程序发送“ 这时存放邮件内容的字符串数组中已接收到整个邮件原文。然后调用mailParse函数分析该数组,找出相关指令。
程序2中给出了mailParse函数的实现。该函数首先检索“Subject:”字符串,如果找到则存储相应的标题内容。然后将标题串与目标所支持的命令(PING、SENSOR和RESET)相比较,并调用相应的处理函数。
实例代码中每个处理函数都包含了相同的基本处理过程。首先分配一个邮件标题结构,根据希望提供的响应填入该结构的相关字段,然后调用mailSend函数发送邮件(参见示例程序3)。sendResponse 和processCommand函数的功能十分显而易见。
函数sendSensorData略有不同,它发送的是HTML格式的文本。除了邮件正文不同外,其内容类型标志也不同:普通正文的内容标志为“text/plain”,而HTML格式的内容标志为“text/html”,表示邮件中可能包含HTML标记。这些处理程序十分简单,但可以进行扩展以支持任何电子邮件客户程序所允许的嵌入标记(包括图象、声音等数据的传输)。 MailSend函数实现SMTP客户端的协议处理。这基本上是服务器端代码的反向处理。
另外值得注意的是客户报头文件,它定义了mailHeader结构(见实例程序1)。该结构中多数的字段都一目了然,其中一个特殊的字段是specialHeaders。如果电子邮件客户程序把邮件中所有的标题域都显示出来,将发现许多不常见的内容,多数都可在IETF的“通用互连网消息标题”(RFC-2076)文档中找到。通过specialHeaders字段可调整电子邮件的处理。例如可采用“Priority: Urgent”标题注明邮件的重要性,或采用“Content-MD5:”标题(以及相应的校验码)来保证在传递过程中邮件的内容未发生改变。
测试设置
实例代码可在Linux上直接编译并运行。编译前必须先配置两个参数程序才能正常运行(在client.h文件中)。
第一个参数是SMTP GATEWAY宏定义,它设定嵌入式SMTP客户程序发送电子邮件的目标,一般是用户有发送或接收帐号的SMTP网关,或者是提供电子邮件中转服务的网关。该参数可设为一个IP地址或一个域名(mailSend函数中的代码具备域名解析功能)。
第二个可配置的参数是SOURCE_E-MAIL_ADDRESS,该参数并不十分关键,它表示回复邮件中“From:”字段的内容(即发送方的标志)。这些参数设置好以后,只需简单地“Make”就可生成“Tinyms”可执行程序镜像。 发出邮件的电子邮件桌面程序必须将其SMTP网关(或发送服务器)配置为嵌入式设备的IP地址。当用软件发送电子邮件时,无论接收方在哪里,邮件都要首先经过预先设好的SMTP网关(即嵌入式设备)。嵌入式设备并不关心地址,它只是处理所有收到的邮件,并把回复内容传给发送方。注意标题域(Subject:)的内容是要执行的命令(如SENSOR或者PING)。在列举的实现中忽略了邮件的正文,但只需稍加修改旧可对正文进行处理,因为整个邮件的原文都存放在字符数组中。
本文小结
现在可以向嵌入式设备发送电子邮件并获得响应了,但这只是一个最基本的配置,它给传统的通信模式提供了一种有趣的替代。我们可对这一实现进行多种扩展,例如支持在电子邮件正文中嵌入XML消息(通过某种XML分析器);还可通过在接收或发送的邮件中附加Base64或“Quoted-Printable MIME”编码/解码处理功能来支持二进制附件。利用后者可提供向嵌入式设备发送软件更新或接收采集的二进制数据的功能(在传统的图像等多媒体数据之外)。最后,不用任何额外的改变,就可由嵌入式设备在异常情况下发送电子邮件报警。
作者简介:
M. Tim Jones是Emulex公司的软件工程师。他从1986年到现在一直从事嵌入式软件开发,其范围十分广泛,从航空设备的操作系统内核到地面嵌入式网络,无所不及。Tim获得了计算机科学的学士和硕士学位。可通过mtj@与他联系。
作者:M. Tim Jones
Emulex公司
京公网安备 11011202001138号
