Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1093978
  • 博文数量: 286
  • 博客积分: 3124
  • 博客等级: 中校
  • 技术积分: 5186
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-24 23:42
个人简介

Bomi

文章存档

2015年(1)

2013年(1)

2012年(281)

2008年(3)

分类: 系统运维

2012-02-05 11:14:24

第 1 部分

本文将指导开发人员使用 JSR 180 API 通过 SIP 协议进行异步通信。

移动应用程序需要从服务器接收信息,或者通过服务器从移动用户处接收信息。当移动设备与服务器进行同步通信时,一切工作都会正常进行。您只需要打开连接发送请求,服务器将使用相同的连接返回响应。

HTTP 协议非常适合同步事务,当人们访问遍布各地的网站时,这种同步事务每天都会发生十亿次。然而,当连接不存在,但 Web 服务器却要联系 Web 浏览器时,问题就会变得很棘手。对于北美洲而言,现在正处在税收时期,请考虑下面这个问题。如果使用 Web 应用程序提交税务信息,那么您是如何获取接受或拒绝税务文件的响应信息呢?您可以通过异步协议(如 SMTP,或称作电子邮件)获取响应,或者在同步协议(如 HTTP 协议)中采用轮询机制来检查税务应用程序的状态。

考虑一个经典的问题:如果移动应用程序需要接收一些事件的通知,您就需要使用同步协议或异步协议来执行轮询操作。如果您使用过 Java ME,那么应当知道 MIDP 1.0 之后的所有 Java ME 设备都提供了对 HTTP 协议的支持。因此,本文的目的在于让开发人员能够使用 JSR 180 API 实现基于 SIP 协议的异步通信。幸运的是:JSR 180 是 MSA 标准 的一部分,因此将会有越来越多的移动设备支持此 API。

在下面的示例代码中,我将展示两个分别使用 SIP 和 JSR 180 API 的 MIDlet。但在开始之前,您将了解运行此示例所需的所有资源:

    * Sun Wireless Toolkit 2.5 for CLDC

是的,您甚至不需要通过两台计算机来运行发送和接收应用程序。可以在同一计算机上同时运行这两个示例。


SipReceiver.java MIDlet

本文假设您具备创建 MIDlet 的经验,因此不再涉及有关 MIDlet 生命周期或构造函数的内容。如果需要,您可以通过以下教程快速掌握 Java ME 的基础知识:学习资源:MIDlet 生命周期、无线开发教程,第 1 部分、移动 Java 技术介绍。让我们看代码的第一行:

import javax.microedition.sip.*;

public class SipReceiver extends MIDlet implements CommandListener{

        public Display display;
        public long startTime;
        public Form. form;
        public TextField portTextField;
        public ImageItem userImageItem;
        public Image userImage;
        public Command startCommand;
        public Command exitCommand ;
        public SipConnectionNotifier scn = null;
        public SipServerConnection ssc = null;

将 SipServerConnection 类绑定到端口并监听发出的请求。为了使这一切起作用,SipServerConnection 需要协同 SipConnectionNotifier 一起工作。SipConnectionNotifier 是您需要实现的一个接口,当您的 MIDlet 接收到 SIP 请求时,它可以向您发出通知。从以下类声明中可以看出,我并没有实现 SipConnectionNotifier 接口,因为我选择使用内部类来处理所有的 I/O 操作。以下代码片段显示了内部类 DataTransfer 的详细内容。

   class DataTransfer extends Thread implements SipServerConnectionListener {

      public void run(){

         try {
            if(scn != null)
               scn.close();
            scn = (SipConnectionNotifier) Connector.open("sip:" + portTextField.getString());
            scn.setListener(this);
            form.append("Listening to port: " + scn.getLocalPort());
         } catch(Exception ex) {
            ex.printStackTrace();
         }
      }

      public void notifyRequest(SipConnectionNotifier scn) {
         try {
            ssc = scn.acceptAndOpen();
            if(ssc.getMethod().equals("MESSAGE")) {
               String contentType = ssc.getHeader("Content-Type");
               String contentLength = ssc.getHeader("Content-Length");
               int length = Integer.parseInt(contentLength);
               if((contentType != null) && contentType.equals("text/plain")) {
                  InputStream is = ssc.openContentInputStream();
                  int i=0;
                  byte testBuffer[] = new byte[length];
                  i = is.read(testBuffer);

                  String message = new String(testBuffer, 0, i);

                  form.append(new StringItem("Subject:", ssc.getHeader("Subject")));
                  form.append(new StringItem("Message:", message));
               }
               ssc.initResponse(200);
               ssc.send();
                }
       
         } catch(IOException ex) {
            form.append("Exception: "+ex.getMessage());
         }
      }
   }

应该注意两个明显的问题:

    * 内部类扩展了 Thread 类,因为需要在单线程中执行所有的阻塞 I/O 操作。
    * 内部类实现了 SipConnectionNotifier,这在前面已解释过。由于该类实现了 SipConnectionNotifier ,因此在接收到新请求时会调用 notifyRequest() 方法。

您已经了解了接收 SIP 消息所需的大部分工作。接下来,我们来看看发送消息所需的代码。


SipSender.java MIDlet

和前面的示例相同,我将使用内部类实现所有繁重的任务。我们直接查看内部类代码部分,了解其实现细节。

   class DataTransfer extends Thread implements SipClientConnectionListener{

      public void run() {
         SipClientConnection sc = null;
         try {
            sc = (SipClientConnection) Connector.open(addressTextField.getString());
            sc.setListener(this);
            String message = messageTextField.getString();
            sc.initRequest("MESSAGE", null);
            sc.setHeader("From", addressTextField.getString());
            sc.setHeader("Subject", subjectTextField.getString());
            sc.setHeader("Content-Type", "text/plain");
            sc.setHeader("Content-Length", "" + message.length());
            OutputStream s = sc.openContentOutputStream();
            os.write(message.getBytes());
            os.close(); 
       
         } catch(Exception e) {
            e.printStackTrace();
         }
      }

      public void notifyResponse(SipClientConnection scc) {
         try {
            scc.receive(1);
            form.append("notifyResponse: "+scc.getStatusCode()+" "+scc.getReasonPhrase());
            scc.close();
         } catch(Exception e) {
            form.append(e.getMessage());
         }
      }
   }

再次指出几个问题:

    * 我们采用内部类扩展 Thread 类是出于性能原因,因为在生成 I/O 请求时,您不希望所有的应用程序都暂停运行。
    * 我们需要实现接口 SipClientConnectionListener,这要求实现回调方法 notifyResponse()。这样,我们可以检查消息的状态码。SIP 的状态码和 HTTP 很相似,因此状态 200 就意味着已成功接收并理解了您的请求。


结束语

如您所见,借助 JSR 180 API,您可以轻松地使用 SIP 协议发送和接收消息。最重要是:SIP 响应代码是以 HTTP 为模型的,因此在使用该协议的过程中您会觉得非常惬意。在第 2 部分,我们将深入探索 SIP 协议,并了解使用注册器或代理的优势。
阅读(1707) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~