MIDlet-Push-<n>Q?/b>push注册属性名U。MIDlet套g中可以包含多条push注册?lt;n>的数g1开始,q且对于附加的条目必M用连l的序数。第一个发现的~失条目中止列表。Q何剩余的条目都会(x)被忽略?br />ConnectionURLQ被Connector.open()使用的连接字W串?br />MIDletClassNameQ负责连接的MIDlet。指定的MIDlet必须使用MIDlet-<n>记录在描q文件或jar文g的manifest中登记过?br />AllowedSenderQ一个指定的qo(h)器, (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)它将限制哪些发送者能够能正当启动h的MIDlet?br />
MIDP 2.0 规范定义?jin)数据报和socket带内q接的语法。当其他规范为其他连接类型定义push 语义Ӟ它们必须既定义过滤器域期望的语法Q又定义q接URL字符串的期望格式?br />
在jad文g中,一个push注册的典型例子,使用socketq接Q类g如下Q?br />MIDlet-Push-1: socket://:77, com.sample.SampleApplication, *.
q个CZ描述W条目在77端口处保存一个流套接字,q且允许所有的发送者?br />
从服务器推信息到Ud讑ֈ?x)带来一些问题:(x)如果我们惛_送信息到一个在指定端口注册?jin)监听流套接字的特定讑֤Q我们必ȝ道那个移动电(sh)话的无线|络IP。因为在无线|络中,很多手机不用始l连接环境(有时候,提供商不支持讑֤中网l中的静(rn)态IPQ,发送信息到讑֤是有问题的。如果我们不知道讑֤的无UIPQ我们将不能使用套接字连接从服务器发送信息到讑֤?br />
短信服务QSMSQ在q种情况下派上了(jin)用场。用SMSQ我们指定目标设备的?sh)话L(fng)Q因此在q种情况下,我们不需要知道设备的IP地址。但是,使用SMS作ؓ(f)触发器同样会(x)带来一些问题:(x)因ؓ(f)MIDP2.0规范只定义了(jin)针对数据报和套接字带内连接的语法Q而没有针对SMSq接的,所以不保证所有支持MIDP2.0的设备都能用SMS作ؓ(f)触发器来q行push注册。但无线消息APIQWMA1.1Q-一个在MIDP上能支持SMS的的可选包Q现在得到很多移动设备的支持Q所以有更大的可能性,SMS作ؓ(f)push注册机制的触发器得到很多设备的支持。对于这文章,我用Nokia 6600Ud?sh)话Q它是支持SMS作ؓ(f)push注册机制的触发器的?br />
另外Q从服务器发送一条SMS消息到设备不是简单直接的Q因为有很多途径存在。SMS服务提供商提供APIQ或者暴露服务URLQ,通过q些API你能从你的服务器端应用程序发送消息到你指定的Ud?sh)话上。但q种Ҏ(gu)依赖于SMS服务提供商和它特D的计划。可选的方式是用一个GSM调制解调器,q样你需要GSM调制解调器与你的服务器端应用E序q行交互。在q篇文章中,我将使用一个开源的产品QSMSLib for Java V1.0Q原名jSMSEngineQ,它能使GSM调制解调器与你的Java服务器端E序q行交互?br />
另一个在此需要注意的要点是一条简单的SMS消息不?x)激zMIDlet。我们必d送SMS消息到MIDlet注册监听的特定的端口。因此被用来发送SMS消息的YӞ或SMS服务提供商)(j)必须能够它发送到讑֤指定的端口。SMSLib for Java v1.0 支持q一功能?br />
当我们用GSM调制解调器方案,我们必须?jin)解GSM调制解调器将在内部用SIMQ订戯别模块)(j)卡来发送SMS消息。SIM卡依赖于某个Ud服务提供商。因此每条SMS短信带来与从常规GSMUd?sh)话发送消息同L(fng)p。正相反Q对于一个企业应用Q依赖于服务计划Q,通过提供商的SMS|关发送批量SMS消息?x)被证实更节省开销。但是,如果应用E序不需要发送大量SMS消息来出发MIDletQ那么GSM调制解调器方案会(x)是有效的开销Qƈ能从Ud服务提供商那里取消特D的扚wSMS服务依赖?br />
虽然我徏议ؓ(f)?jin)近期的产品使用购买一个单独的GSM调制解调器,但是试此行Z要求够买。通常圎ͼ很多GSMUd?sh)话模型带有一个内|的GSM调制解调器。那些移动模型中的Q何一个都能够作ؓ(f)GSM调制解调器,来代替单独的调制解调器。在q篇文章中,我用另外一个Nokia 6600Ud?sh)话Q而不是一个单独的GSM调制解调器,因ؓ(f)Nokia 6600有一个内|的GSM调制解调器?br />
现在Q让我们开发一个实例程序,是我们能够从一个Java服务器端应用E序发送一条SMS消息C个移动电(sh)话的指定端口Qƈ自动启动Ud讑֤中的一个MIDlet?br />
使用push注册特征开发客L(fng)MIDlet
Z(jin)开发客L(fng)Q我们用Sun Java Wireless ToolkitQ原名ؓ(f)J2ME Wireless ToolkitQ。我使用版本2.2。这个品是免费的,可以从Sun的网站下载。ؓ(f)?jin)安装和q行此工具包Q你必须在你的机器上装有J2SE 1.4.2_02或更新的版本?br />
我用Windows 2000 Professional 操作pȝ?br />
安装Sun的工具包后,按照如下描述的步骤:(x)
1Q从开始菜单打开KToolBarQ选择E序Q然后J2ME Wireless Toolkit 2.2Q然后KToolbar。将?x)打开一个应用程序窗口,如图2所以?br />

?. 打开KToolbar
2Q现在,在刚才打开的窗口中点击新徏工程图标。会(x)打开一个弹出窗口;在那里你可以指定工程名称和MIDletcd。在工程名称中输入MySamplePushRegistryProjectQ在MIDletcd中输入com.sample.MySamplePushRegistry?br />

?. 新徏一个工E?br />
3Q在步骤2后,?x)自动出现另一个弹出窗口,它将允许你设定项目的其他讄。确保你在API 选择标签中。在此标{中Q从目标q_下拉菜单中选择JTWIQ如果还没有选择Q。同L(fng)保CLDC 1.0单选按钮被选中。不要钩选Mobile Media API多选框Q因Z?x)用Q何跟多媒体有关的APIQ。请参考图4?br />

?. 讄API首选项
4Q现在进入push注册标签。点?yn)L加按钮。将?x)出C个弹出窗口。在q接URL域中输入sms://:50001Q在cd中输入com.sample.MySamplePushRegistryQ在允许发送者域中输?。请参考图5?br />

? 讄push注册的属?br />
5Q在步骤4后,一个条目将?x)被加入到父H口中。如?所C?br />

?. 讄push注册的属性(l)(j)
6Q现在进入许可标{。单?yn)L加按钮。从许可?wi)中选择javax/microedtion/io/Connector/smsq单击OK。重复相同?tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)的步骤来添加许可javax/wireless/messaging/sms/receive ?javax/microedtion/io/PushRegistry?br />
7Q在步骤6后,三项许可被d到应用程序中。如?所C?br />

?. d许可
8Q现在进入用户定义标{。这里,我们d用户定义的变量,q将包含SMS端口。从我们的程序,我们查阅此用户定义变量来dSMS端口。在此标{中Q单?yn)L加按钮。打开一个弹出窗口。输入SMS-Port作ؓ(f)属性名U。选择OK。出C(jin)最初的弹出的窗口。输?0001作ؓ(f)SMS-Port的倹{如?所C?br />

?. d定制属性SMS-Port
9Q现在,在设|窗口中单击OK。这个动作将带回到KToolbar?br />
10Q在步骤9后,如果你观察由以上步骤产生的jad文gQC:/WTK22/apps/MySamplePushRegistryProject/bin/MySamplePushRegistryProject.jadQ假设J2ME Wireless Toolkit 2.2被装在目录C:/WTK22中)(j)Q你?x)找到在前面步骤中设定的完整配置。所有条目中最重要的一个如下:(x)MIDlet-Push-1: sms://:50001, com.smaple.MySamplePushRegistry, *. 此条目确保你的应用程序监?0001端口上的SMS消息?br />
现在Q让我们着gMIDlet应用E序的代码。这里,我仅仅提供MIDlet的一部分代码片断?L(fng)资源来下载在此应用程序中使用的所有代码?br />
public class MySamplePushRegistry extends MIDlet
(tng) (tng) implements CommandListener, Runnable, MessageListener {
(tng) (tng)
(tng) (tng) //....
(tng) (tng)
(tng) (tng) public void startApp() {
(tng) (tng) (tng) (tng) (tng) (tng)smsPort = getAppProperty("SMS-Port");
(tng) (tng) (tng) (tng) (tng) (tng)String smsConnection = "sms://:" + smsPort;
(tng) (tng) (tng) (tng) (tng) (tng)if (smsconn == null) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) try {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)smsconn = (MessageConnection)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Connector.open(smsConnection);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)smsconn.setMessageListener(this);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) } catch (IOException ioe) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)ioe.printStackTrace();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng)}
(tng) (tng) (tng) (tng) (tng) (tng)display.setCurrent(resumeScreen);
(tng) (tng) }
(tng) (tng) public void notifyIncomingMessage(MessageConnection conn) {
(tng) (tng) (tng) (tng) (tng) (tng)if (thread == null) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) thread = new Thread(this);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) thread.start();
(tng) (tng) (tng) (tng) (tng) (tng)}
(tng) (tng) } (tng) (tng) (tng) (tng)
(tng) (tng) public void run() {
(tng) (tng) (tng) (tng) (tng) (tng)try {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) msg = smsconn.receive();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) if (msg != null) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)if (msg instanceof TextMessage) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) content.setString(((TextMessage)msg).getPayloadText());
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)}
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)display.setCurrent(content);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng)} catch (IOException e) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) e.printStackTrace();
(tng) (tng) (tng) (tng) (tng) (tng)}
(tng) (tng) }
(tng) (tng) //other methods to follow
}
在这个片断中Q如下要点值得注意Q类MySamplePushRegistry集成?jin)MIDlet。这个类实现?jin)CommandListenerQRunnable和MessageListener接口。在MIDlet的startApp()Ҏ(gu)中,我们使用getAppProperty()Ҏ(gu)得到SMS-Port属性的倹{我们也使用Generic Connection FrameworkQGCFQ创Z(jin)一个连接来监听SMS消息。GCF的Connectorcȝopen()Ҏ(gu)创徏?jin)SMSq接。如果一个消息到达了(jin)QnotifyIncomingMessage()Ҏ(gu)?x)被调用Q它?x)创建和启动一个线E(如果q没有被创徏Q。在U程的run()Ҏ(gu)中,E序{待一条消息(smsconn.receive()Q。当消息被接受到Q我们得到原始的消息q在AlertcM讑֮消息。在现实生活的应用程序中Q用户通常打开一个屏q来处理消息?br />
一旦你的代码准备好?jin),使用KToolbar中的创徏图标来创建它。在~译和无错误预验证创Z后,你需要把应用E序打包成一个JAR。ؓ(f)?jin)完成这个Q务,选择工程菜单Q然后包Q然后创建包?br />
在把应用E序部v到真实设备之前,我们先测试程序是否在模拟器中q{正确。选择工程菜单Q然后通过OTAq行。这个步骤实际上是模拟MIDlet的over-the-air安装。图9的顺序图描述?jin)全部的q程。保持此模拟器窗口打开?br />

?. 通过over the airҎ(gu)在模拟器中安装应用程?br />
现在Q在KToolbar中进入文件菜单,q择Utilities。得C个弹出窗口,如图10所C?br />

?0. 打开Utilities
单击WMAQ然后打开控制台。打开?jin)另一个弹出窗口:(x)

?1. 打开WMA Utilities 控制?br />
在窗口中选择发送SMS按钮。窗口的内容会(x)改变Q如?2所C。在选择客户端区域内选择+5550000作ؓ(f)?sh)话L(fng)。在端口文本框中Q输?0001。在消息域中Q输入Hi Test Message。现在单d送按钮?br />

?2. 从Utilities发送SMS消息
如果在以上步骤中Q每一件事都运行良好,那么模拟器窗口,如图13所C,会(x)昄一个消息到达了(jin)模拟Ud?sh)话Q告诉用h息到辑ֈ?jin),q等到批准?br />

?3. 模拟器MIDlet被SMS消息Ȁz?br />
如果你在模拟器上选择YesQMIDlet?x)自动启动,”Hi Test Message”会(x)昄在模拟器中,如图14所C?br />

?4. 模拟器MIDlet接受到SMS
接下来的步骤事在真实讑֤上安装MIDlet。你可以使用OTA安装应用E序。详l内容请查阅Sun的工具包文档。除?jin)OTAQ我们可以电(sh)~?U外U?蓝牙技术来安装MIDletQ如果设备支持那些选项。作Z个客L(fng)讑֤Q我使用Nokia 6600Q这是支持红外线技术的Qƈ且因为我有一个红外线适配器,我用红外线技术在Nokia 6600中安装MIDlet?br />
如果以上步骤q行良好Q你的客L(fng)应用E序准备就l了(jin)。现在是时候来开发服务器端应用程序了(jin)Q实际上Q它?yu)发送SMS消息l监?0001端口的MIDlet?br />
开发服务器端应用程序来SMS消息发送到特定的设备端?br />如前所qͼZ(jin)开发服务器端与GSM调制解调器交互的的代码,我用开源的SMSLib for JavaQ?它用关注指令(AT指o(h)Q与GSM调制解调器进行交互。它同时也用Java通信API或RxTx与用的操作pȝ通信Qƈ与外部设备(GSM调制解调器)(j)交谈来发送AT指o(h)?br />
Z(jin)发送消息到指定的端口,用户数据和协议数据单元(PDUQ的用户数据标题指示QUDHIQ域都必被修改。SMSLib在内部完成了(jin)它,所以发送SMS消息引v的复杂度都被包装在SMSLib的代码内。如果你对观察消息是如何被正发送的感兴,你可以独自仔l检查SMSLib的代码?br />
按照如下的步骤来完成服务器的~码和部|Ԍ(x)
1Q从SMSLib|站下蝲SMSLib代码。下载时Q确保你下蝲的是SMSLib-Java-v1.0.1.zip。SMSLib for Java可以跟Java通信API或RxTx一起用。最q,Sun撤消?jin)?jin)对Java通信API Windows版的支持Q所以用RxTx?x)更好。但如果你已l有?jin)Java通信APIQ你同样可以用它和SMSLib一赯行。在q篇文章中,我将详述以上两种q行实例E序的方法?br />
2Q以Java通信API 2.0作ؓ(f)开始,首先Q确保你已经正确安装?jin)API。解压javacomm20-win32.zip。在commapi子目录中Q你找到如下文Ӟ(x)
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)javax.comm.properties
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)win32com.dll
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)comm..jar
把javax.comm.properties拯C的Javaq行时环境的lib目录中。把win32com.dll拯C的JRE的bin目录中。当q行M使用SMSLib的程序时Q确保comm.jar在classpath中?br />
Z(jin)保证Java通信API被正的安装?jin),从命令框中进入到commapi\samples\BlackBox目录中。按如下方式讄PATH变量Q以我ؓ(f)例,JRE的家目录为C:\j2sdk1.4.2_03\jre。根据你的JRE讄做相应的改变?br />
讄PATH=.;c:\j2sdk1.4.2_03\jre\bin;。现在,使用如下命o(h)来运行Java 黑盒E序Q?br />java -classpath .;../../comm..jar;BlackBox.jar; BlackBox?br />
如果Java通信API被正的安装?jin),那么如?5所C,?x)出C个显CZ机器的可用串口(COM端口Q的SwingH口。关闭窗口之后,命o(h)框将?x)包含一些跟你可用的COM端口相关的行Q如下面的示例命令提C出所C。记住,依赖于你的PC上的可用端口QSwingH口和命令行提示的内容可能会(x)有变化。但重要的是Q如果你能够看到GUI和在命o(h)提示框中的如下行Q就象下面所C)(j)Q你可以假设Java通信API已经正确安装?jin)。在q个试之后Q关闭SwingH口来中止黑盒程序?br />

?5. 试Java通信API的安?br />
实例命o(h)提示框输出:(x)
COM1: (tng) (tng)PORT_OWNED
COM2: (tng) (tng)PORT_OWNED
Closing port 1 (COM2)
Closing COM2
Closing port 0 (COM1)
Closing COM1
3Q现在,是时候把GSM调制解调器连接到你的?sh)脑上?jin)。我使用一部Nokia 6600Ud?sh)话作?f)GSM调制解调器。Nokia 6600没有串口q接器(COM端口q接器)(j)。但是,它提供了(jin)U外U技术连接到?sh)脑Q然后作为GSM调制解调器。如果你有一部有串口直接q接器的?sh)话Q那样用v来会(x)更简单。一般地Q?tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)实际的GSM调制解调器会(x)提供串口q接器。但是如果你的设备缺串口连接器Q但包含一个内|的GSM调制解调器ƈ能用红外线或蓝牙技术连接,q种选择也能起作用?br />
Z(jin)在没有物理COM端口的情况下Q在功能上实现COM端,你必d一个虚拟的COM端口映射C的红外线或蓝牙连接上。SMSLib需要一个兼容的GSM?sh)话或GSM调制解调器。如果提供了(jin)调制解调器的能力Q大多数GSM?sh)话都能被用。SMSLib使用串行q接(物理或模拟,比如蓝牙Q红外线QUSB{?来与GSM调制解调器通信。通过Nokia 6600Q?你可以用SMSLib来发送SMS消息Q但是因为Nokia 6600把传入的消息储存在记忆卡里而不是SIM卡中Q用这U模式将不能接受到这些消息。同PNokia 6600不允总记忆卡中使用AT指o(h)来读取消息。但是,我们仅仅需要发送SMS消息来激zL们的MIDletQNokia 6600能够成功的完成这些(不需要接收SMS消息Q。对于用红外线或蓝牙技术连接的?sh)话来说Q最重要的是红外线或蓝牙连接映到一个虚拟COM端口。参考你的移动电(sh)话的文档Q查明它是否支持虚拟COM端口映射?br />
以我ZQ我在我的PC上安装了(jin)Nokia PC 套g。ؓ(f)?jin)从我的PCq接Nokia 6600Q我使用一个外部USBU外适配器。因此,Z(jin)q种情况Q我也在PC上安装了(jin)U外UK动?br />
现在Q我用PC上的USB端口q接到外部红外适配器。在Nokia 6600讑֤上,我选择菜单Q然后连接,然后调制解调器。通过U外U连接的选项在调制解调器下面。现在,我选择选项“连接”,q把Ud?sh)话攑֜U外适配器的有效范围之内?br />
4Q下一步是验证从PCQ我们能够用AT指o(h)讉KGSM调制解调器。ؓ(f)此,选择开始菜单,然后E序Q然后附Ӟ然后通信Q然后超U终端。会(x)打开一个对话框Qƈh一个逻辑名称。提供Q何你愿意提供的名字。ؓ(f)?jin)方便,我提供名字“GSM Modem”。选择OK?br />

?6. 打开l端
5Q另一个弹出窗口出现。在使用q接的下拉菜单中Q选择COM端口名称Q虚拟的或实际的Q,GSM调制解调器将通过此端口连接到PC。以我ؓ(f)例,是COM4?br />

?7. 在超U终端中选择COM端口
6Q在下一个对话框中(COM端口的属性)(j)Q只需单击OK?br />
7Q现在,你会(x)被带C个窗口,你将在此H口中输入一些命令(以我们ؓ(f)例,我们输入AT指o(h)Q。输入如下命令来试q通性-但是CQ当你输入指令的时候,不会(x)在控制台中写入Q何东西:(x)AT+CPMSQ??br />
要点Q不要在l端中输入Q何未知的命o(h)。这可能?x)永久性损坏你的移动设备或擦去所有的数据?br />
如果一切顺利,你将能看C些输出,如图18所C。输出可能会(x)不尽相同Q但是没有输出,输出错误Q或l端没有响应都代表这q通性的错误?br />

?8. 在超U终端中执行AT指o(h)
8Q现在从呼叫菜单Q用断开q接命o(h)从超U终端断开q接?br />
9Q完成了(jin)如上的步骤后Q我们可以准备写JavaCZE序?jin)。此E序发送SMS消息到我们刚才配|的的GSM调制解调器的指定端口上:(x)
import org.smslib.*;
public class SendMessageWithPortsSMSLib {
(tng) (tng) public static void main(String[] args) {
(tng) (tng) (tng) (tng) (tng) (tng)CService srv = new CService("COM4", 9600, "", "");
(tng) (tng) (tng) (tng) (tng) (tng)System.out.println("SendMessage(): sample application.");
(tng) (tng) (tng) (tng) (tng) (tng)System.out.println(" (tng) (tng)Using " + srv._name + " v" + srv._version);
(tng) (tng) (tng) (tng) (tng) (tng)try {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) srv.setSimPin("0000");
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) srv.connect();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) srv.setSmscNumber("");
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) COutgoingMessage msg =
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)new COutgoingMessage("+9198301...", "Message from smslib API.");
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) msg.setMessageEncoding(CMessage.MESSAGE_ENCODING_7BIT);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) msg.setSourcePort(0);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) msg.setDestinationPort(50001);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) srv.sendMessage(msg);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) srv.disconnect();
(tng) (tng) (tng) (tng) (tng) (tng)}
(tng) (tng) (tng) (tng) (tng) (tng)catch (Exception e) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) e.printStackTrace();
(tng) (tng) (tng) (tng) (tng) (tng)}
(tng) (tng) (tng) (tng) (tng) (tng)System.exit(0);
(tng) (tng) }
}
在如上的代码片断中,我们首先使用4个参数来创徏cCService的一个实例。第一个参Cؓ(f)COM端口的名U。(以我ZQ这里是COM4Q因为我的GSM调制解调器是q接C个虚拟的COM端口的。确保根据你的COM端口名称来改变这里的倹{)(j)W二个参数指定L特率。当调制解调器连接时你会(x)发现q一限制。第三个参数指定Ud/GSM调制解调器的构成。第四个参数指定模式。在一个特定的构成和模式需要不同的AT指o(h)集来与GSM调制解调器交互的地方Q第三和W四参数有时启动很重要的作用。例如,对于Sony Ericsson模式Q需要一个不同的AT指o(h)集和逻辑Q因此,伴随着jSMSEngine发行版,你能扑ֈ一个单独的对于Sony Ericsson的处理包。对于特定类型的构成和模式,jSMSEngine有不同的处理包。对于NokiaQ缺省的处理包对于Nokia 6600 和我们的目的已经_好了(jin)。因此,我没有对W三和第四个参数指定M倹{?br />
CService被初始化之后Q我们用connect()Ҏ(gu)q接到GSM调制解调器。我们设|SMSC数字QSMS中心(j)数字Qؓ(f)I。这?x)被SIM卡得到。在那之后,我们使用cCoutgoingMessage()创徏一个发出的消息。COutgoingMessage()的构造函数需要两个参敎ͼ(x)发送消息的讑ֈ数字和消息本w。在一个典型的实际的应用程序中Q一些类g数字代码的指C符?x)被作?f)SMS消息发送;Ҏ(gu)那个代码Q在MIDlet端会(x)发生一些动作。另外一个要Ҏ(gu)setDestinationPort()Ҏ(gu)Q在q里我们讑֮目标端口?br />
?9展示?jin)详l的建立q程?br />

?9. 详细的徏立过E?br />
重要注解QSMSLib在CLogger.java中用了(jin)J2SE 5.0的API。CLogger.java中有一行用PrintStream的构造函敎ͼq用java.io.Filecd作ؓ(f)参数。这个PrintStreamcM的构造函CJ2SE 5.0才有支持。但是由于我使用J2SE 1.4Q我把那一行从Qstream = new PrintStream(new File(filename)); Ҏ(gu)Qstream = new PrintStream(new FileOutputStream(filename));
改变之后Q我构徏?jin)SMSLib提供的源代码Qƈ创徏?jin)新的JAR使用JRE 1.4.2?br />
10Qؓ(f)?jin)编译示例程序,保在你的classpath中有新的JARQ是你在修改CLogger代码后生成的Q和comm.jar。然后编译示例应用程序?br />
11Q编译完成之后,q行应用E序。确保之前步骤提到的JAR在classpath中。如果一切顺利,你能够看C安装在另外一个设备中MIDlet已经自动启动?jin),q显CZ的消息?br />
现在Q让我们看看如何使用RxTx来代替Java通信API 2.0。你可以从SMSLib下蝲RxTx。当使用RxTx的时候,我们需要注意如下几点:(x)
1Q拷贝RXTXComm.jar刎ͼJDKDIRQ\jre\lib\ext目录Q拷贝rxtxSerial.dll文g刎ͼJDKDIRQ\jre\bin目录?br />2Qؓ(f)?jin)用,SMSLib同Java通信API一h包,但是q行一部分的代码修改Q我们也能让它跟RxTx一起用。ؓ(f)?jin)让SMSLib同RxTx一起用,修改CSerialDriver.javaq删除行javax.comm.*;。添加行import gnu.io.*;。然后重新生成?br />3QRxTx也支持Win32。当我写q篇文章的时候,RxTx能很好的支持物理串行q接Q但是对于“虚拟”串行端口则有些例外Q例如,通过蓝牙/U外U?USBq接模拟串行端口。但是,在显C生zȝ情况中,你不?x)用一个移动电(sh)话作制解调器Q而是一个真实的GSM调制解调器,它将通过真实的COMQ串行)(j)端口来连接。这不?x)成为问题。现在,以我ZQ在发送SMS消息时我接受C(jin)一些错误,因ؓ(f)我的U外U连接有一个虚拟的端口映射。ؓ(f)?jin)消除那些错误,我在CSerialDriver中注释掉?jin)一些行。特别的Q找到outStream.flush();Q注释掉Q然后重新生成?br />4Q现在,按照上面列表中的步骤3开始。在步骤11中,保当运行SendMessageWithPortsSMSLib的时候,在你的classpath中有最q生成的JARQ对于RxTx的改变)(j)Q同时保证用RXTXcomm.jar和rxtxSerial.dll文g代替Java通信API的comm.jar和相应的dll文g?br />
注意的要点:(x)因ؓ(f)SMSLib使用Java通信APIQ或者RxTxQ这些会(x)Ҏ(gu)作系l进行本地调用,我徏议不要将q些代码直接嵌入到应用程序服务器或Web服务器。一个可选的解决Ҏ(gu)是将q些代码嵌入C个单独的RMIQ远E方法调用)(j)服务器或Web service服务器,然后从应用服务器来访问他。但是,因ؓ(f)我们使用GSM调制解调器,SMS的发送速度很低Q所以如果我们直接调用接口(RMI或Web serviceQ,最好用异步设计。例如,当你试着发送一条消息到讑֤Q将必须的信息(UdL(fng)Q端口,消息{)(j)攑ֈ一个Java消息服务队列中。写一个消息驱动的bean来采集消息,然后使用一个Web service来调用服务(嵌入在SMS发送代码中Q?br />
我谈C(jin)一U可行的方式Q你可以选择M最适合你的架构的设计。但是当做Q何决定的时候,紧记如下两点Q?br />
使用GSM调制解调器,发送SMS消息的速度不是很快Q依赖与你选择的GSM调制解调器和SMS服务提供商)(j)
SMSLib使用Java通信API或RxTxQ这对操作pȝ发生本地调用
虽然我徏议用两个Nokia 6600Ud讄Q一个作为GSM调制解调器,另一个作为Java ME客户端)(j)Q你可以仅仅使用一个来试此行为。首先,把MIDlet安装在设备上。然后用相同的讑֤作ؓ(f)GSM调制解调器。当发送SMS消息Ӟ把消息发送到与你作ؓ(f)发送消息的GSM调制解调器的Ud讑֤相同的移动号码上。在q中情况下,发送者和接收者移动电(sh)话是相同的?br />
?l?/span>
在这文章中Q你学到?jin)如何用push注册特征来写Java ME应用E序。同Ӟ你也学到?jin)如何从服务器发送一条SMS消息Q然后自动启动MIDlet。ؓ(f)?jin)仅仅测试push注册特征Q你可以使用两部支持MIDP 2.0和W(xu)MA1.1的手机(不需要服务器端SMS pushQ,和Sun Java Wireless Toolkit提供的SMSSend和SMSRecieveCZE序。但是在实际应用E序中,你可能需要从服务器发送SMS消息Q而不是从另一个MIDlet?br />
在本文中展示的代码片断不是很复杂Q搭建环境的步骤却很复杂。但是一旦正地搭徏?jin)环境,你?x)很兴奋的看到使用服务器端SMS pushQpush注册特征在真实的讑֤上运行。如果你在用SMSLib旉CQ何问题,你L可以发布问题和向SMSLib用户l请求帮助。最后,我要感谢SMSLib目的所有者Thanasis Delenikas分n?jin)一些关于SMSLib最q开发中的有价值的信息?br />
????/b>
Srijeeb Roy拥有印度加尔各答Jadavpur大学计算机科学和工程学的学士学位。他目前作ؓ(f)技术架构师Q在Tata Consultancy Services Limited公司的一个基于Java EE的项目中工作。他在Java/Java EE的领域中工作?q以上,在IT工业拥有d多余7q的l验。他Z的公司和客户开发了(jin)多个Java的内部框架。他也工作在多个其他的领域,比如ForteQCORBA和Java ME?br />
资?tng) (tng)?/b>
下蝲文章中的源代码:(x)
http://www.javaworld.com/javaworld/jw-04-2006/push/jw-0417-push.zip
下蝲Sun Java Wireless ToolkitQ?br />http://java.sun.com/products/sjwtoolkit/
下蝲SMSLibQ?br />http://smslib.org/
RxTx主页Q?br />http://rxtx.org/
]]>