程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 用J2ME進行聯網

用J2ME進行聯網

編輯:關於JAVA

J2ME I/O 與聯網:概覽

Java 2 平台,袖珍版(Java 2 Platform,Micro Edition (J2ME))提供了把網絡 上可用的資源擴展到移動空間中的聯網功能。現在,在移動電話或掌上電腦獲取實時股票 報價或最新貸幣匯率是可能的。

javax.microedition.io 中的各個類和接口處理移動信息設備框架(Mobile Information Device Profile,MIDP)的聯網功能,MIDP 則是一個開發移動設備應用程 序的平台。(想了解更多有關 MIDP 的信息,請訪問下面的 參考資料部分,鏈接到我先 前已發表在 developerWorks上的關於這個主題的文章。)

另一方面,java.io 包給 MIDP 提供了輸入/輸出(input/output(I/O))功能。它 的各個類和接口為數據流提供了系統輸入和輸出。這個 J2ME 包是 Java 2 平台,標准版 (Java 2 Platform,Standard Edition(J2SE)) java.io 包的一個子集,它處理低級 別的數據 I/O。

J2ME 網絡連接性最關鍵的方面是移動設備與 Web 服務器間的通信。這種通信本質上 是客戶機/服務器機制,其中移動設備充當 Web 客戶機的角色並有能力與企業系統、數 據庫、公司內部網和因特網建立接口。

J2ME 聯網活動可以按照通信協議分為許多種類別。我們將在以下幾部分中依次討論每 一種類別。

低級別的 IP 聯網

這一類別涉及到套接字、數據報、串口和文件 I/O 通信。基於套接字的通信遵循面向 連接的 TCP/IP 協議。另一方面,基於數據報的通信遵循無連接的 UDP/IP 協議。UDP 為 應用程序提供了不必建立連接就能發送經過封裝的原始 IP 數據報的方法。面向連接的協 議需要源地址和目的地址,與此不同,數據報只需要目的地址。下面是數據報連接用來在 某端口接受數據報的一個 URI:

datagram://:1234

這裡是數據報連接用來在某端口將數據報發送到服務器的一個 URI:

datagram://123.456.789.12:1234

低級別的 IP 聯網還可以處理文件 I/O 並且能夠允許 MIDlet 注冊對本地串口進行網 絡訪問。

安全聯網

J2ME 中的安全聯網涉及到一些為了與基於 Web 的網絡服務進行安全通信而提供的額 外接口。這些安全接口由 IP 網絡上的 HTTPS 和 SSL/TLS 協議訪問提供。

HTTP 聯網

移動設備與 Web 服務器之間基於 HTTP(Hypertext Transfer Protocol,超文本傳輸 協議)進行通信。HTTP 是一個面向連接的請求-響應(request-response)協議,在這個 協議中,必須在發送請求之前設置請求的各參數。

圖 1 說明了移動設備與 Web 服務器間的通信機制。

圖 1. 移動設備與 Web 服務器間的連接機制

連接框架

J2ME 聯網旨在處理移動設備的廣泛頻譜不同的需要。同時,聯網系統必須是特定於設 備的。為了應付這些要求,J2ME 聯網引入了 通用連接框架(generic connection framework)的概念。

通用連接框架的設想是以 Java 接口的形式定義一些能夠覆蓋聯網和文件 I/O 的通用 方面的抽象。這個體系結構廣泛支持各種手持設備,而將這些接口的實際實現留給了各個 設備制造商。設備制造商可以根據其設備的實際功能選擇要在它的特定 MIDP 中實現哪個 接口。

由 Java 接口定義的通用方面分為以下幾種形式的基本通信類型:

基本串行輸入(由 javax.microedition.io.InputConnection 定義)

基本串行輸出(由 javax.microedition.io.OutputConnection 定義)

數據報通信(由 javax.microedition.io.DatagramConnection 定義)

用於客戶機-服務器(client-server)通信的套接字通信通知機制(由 javax.microedition.io.StreamConnectionNotifier 定義)

與 Web 服務器進行的基本 HTTP 通信(由 javax.microedition.io.HttpConnection 定義)

J2ME 中的 URL 處理

J2ME 中的 URL 處理涉及到從移動設備打開一個到 Web 服務器的連接並處理移動設備 到 Web 服務器間的數據 I/O。這個過程發生在下面的階段:

建立(Setup),此時尚未建立到服務器的連接。移動設備准備一堆請求參數並准備接 受和解釋隨後的響應。

已連接(Connected),此時連接已經被建立,請求參數已經被發送並在期待響應。

已關閉(Closed),此時連接已經被關閉。

J2ME 定義了 javax.microedition.io.Connector 類,這個類包含了用於創建所有連 接對象的各個靜態(static)方法。這一任務是通過根據平台名稱和所請求連接的協議動 態地查找一個類來完成的。

在 URL 處理中,Connector.open() 用來打開 URL;它返回一個 HttpConnection 對 象。Connector.open() 方法的字符串(string)參數是一個有效的 URL。URL 字符串由 於通信協議的不同而不同,下面的清單 1 到清單 5 演示了這一點。

清單 1. 調用基於 HTTP 的通信

Connection conn = Connector.open("http://www.yahoo.com");

清單 2. 調用基於流的套接字通信

Connection conn = Connector.open ("socket://localhost:9000");

清單 3. 調用基於數據報的套接字通信

Connection conn = Connector.open("datagram://:9000");

清單 4. 調用串口通信

Connection conn = Connector.open("comm:0;baudrate=9000");

清單 5. 調用文件 I/O 通信

Connection conn = Connector.open("file://myfile.dat");

Connector.open() 方法還可以接受訪問模式(值為 READ、WRITE 和 READ_WRITE ) 以及一個用來表示調用者想要得到超時通知的標志。

在安全的聯網中,當 https:// 連接字符串被訪問時,Connector.open() 就會返回 HttpsConnection 。當 ssl:// 連接字符串被訪問時,Connector.open() 就會返回 SecureConnection 。

無論使用哪一種類型的 URL,調用 Connector.open() 都會打開一個從 Connection 到 java.io.InputStream 的字節輸入流。這個方法用來讀取文件的每一個字符,一直讀 到文件末尾(以 -1 為標志)。如果拋出一個異常,連接和流就會被關閉。

與此相似,為了進行輸出,代表字節輸出流的 java.io.OutputStream 將被從 Connection 打開。

InputStream 和 OutputStream 分別與 java.io.DataInputStream 和 java.io.DataOutputStream 相對應。DataInputStream 讓應用程序用與機器無關的方式 從底層輸入流讀取基本的 Java 數據類型。java.io.DataOutputStream 讓應用程序用可 移植的方式把基本的 Java 數據類型寫到輸出流。

清單 6 說明了如何使用 HttpConnection 從 URL 輸入數據。

清單 6. 使用 HttpConnection 從 URL 輸入數據

String getViaHttpConnection(String url) throws IOException {
     HttpConnection c = null;
     InputStream is = null;
        StringBuffer str = new StringBuffer();
        try {
          c = (HttpConnection)Connector.open(url);
         // Getting the InputStream will open the connection
         // and read the HTTP headers. They are stored until
         // requested.
         is = c.openInputStream();

         // Get the length and process the data
       int len = (int)c.getLength();
       int ch;
       while ((ch = is.read()) != -1) {
         str.append((char)ch);
       }

      } finally {
      if (is != null)
        is.close();
      if (c != null)
        c.close();
     }

一個貸幣兌換應用程序

我們將通過一個貸幣兌換應用程序來說明迄今為止所概述過的概念,這個應用程序將 會顯示美元(U.S. dollar,USD)和英鎊(British pound,GBP)之間最新的匯率。這個 應用程序還會顯示任意與當前日期和當前時間相關的信息。

這個應用程序的 UI 由一個表單( Form )和一個退出(exit)命令組成,該表單嵌 入了代表一個只顯示字符串的 StringItem ,退出命令用於完成調用時讓應用程序退出。

一旦啟動應用程序,URL 請求便已准備就緒。基本的貨幣符號被提供給請求。接下來 ,我們需要打開一個移動設備與 Web 服務器間的 URL 連接。打開一個 HttpConnection 並為數據輸入建立一個 InputStream 。所獲得的數據是一個字符流,這個多字符流附加 在 String 中。產生的 String 代表 HTML 輸出。由於我們的移動設備上的浏覽器不能顯 示 HTML,因而我們將解析 HTML String 來獲取貨幣值以及任何相關的信息。

我們的程序將在 HTML String 中搜索一個特定模式,即 USDGBP 。一旦確定了這個模 式的位置,搜索便查找十進制值。當獲得了小數點的位置後,各個數字值便會被檢索並以 適當的順序排列,從而獲取貨幣值。清單 7 說明了如何獲取貨幣值。

清單 7. 檢索貨幣值

      String retVal = "";
       int dec = 0;
       int index = str.indexOf("USDGBP");
       if (index != -1)
          str = str.substring(index, str.length());
       if ( (( dec = str.indexOf(".")) != -1) && (! (str.endsWith(".")))
       && Character.isDigit(str.charAt(dec+1)) )
{
  String front = "";
  int find = dec-1;
  while (Character.isDigit(str.charAt(find)))
  {
   front += str.charAt(find);
   find--;
   }
  retVal += new StringBuffer(front).reverse().toString();
  retVal += ".";
  String back = "";
  int bind = dec+4;
  while (Character.isDigit(str.charAt(bind)))
   {
   back += str.charAt(bind);
   bind--;
   }
  retVal += new StringBuffer(back).reverse().toString();
}

相關信息也是通過查找某些特定的字符串模式來獲取的。一旦確定了數據在 HTML String 中的位置,一個偏移量便會被應用來獲取日期和時間。這個信息被與原先用於搜 索的字符串模式附加在一起。清單 8 說明了如何獲取相關信息。

清單 8. 檢索相關信息

// Get the time of Currency Exchange and Related information
  int timeIndex = str.indexOf("U.S. Markets Closed.");
  String retTime = "";
  if (timeIndex != -1)
  {
  retTime = str.substring(timeIndex-34, timeIndex);
  retTime += " U.S. Markets Closed ";
  }

清單 9 包括貨幣兌換應用程序的全部代碼。

清單 9. 完整的貨幣兌換示例

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import java.io.*;
import java.lang.*;
import java.util.*;
//A first MIDlet with simple text and a few commands.
public class CurrencyExchange extends MIDlet
        implements CommandListener {
  //The exit commands
  private Command exitCommand;

  //The display for this MIDlet
  private Display display;

  Form displayForm;

  public CurrencyExchange() {
   display = Display.getDisplay(this);
   exitCommand =
   new Command("Exit", Command.SCREEN, 1);
  }
// Start the MIDlet by creating the Form and
  // associating the exit command and listener.
  public void startApp() {
  displayForm = new Form("Exchange Rate");
  displayForm.addCommand(exitCommand);
  displayForm.setCommandListener(this);
try
{
  String result = getViaHttpConnection
  ("http://finance.yahoo.com/m5?a=1&s=USD&t=GBP");
  displayForm.append(" " + result);
}
catch (Exception exc)
{
  exc.printStackTrace();
}
display.setCurrent(displayForm);
  }

  // Pause is a no-op because there is no  background
  // activities or record stores to be closed.
  public void pauseApp() { }
  // Destroy must cleanup everything not handled
  // by the garbage collector.
  // In this case there is nothing to cleanup.
  public void destroyApp(boolean unconditional) { }
// Respond to commands. Here we are only implementing
// the exit command. In the exit command, cleanup and
// notify that the MIDlet has been destroyed.
  public void commandAction(
  Command c, Displayable s) {
   if (c == exitCommand) {
   destroyApp(false);
   notifyDestroyed();
   }
  }

String parse(String str)
{
  // Get the time of Currency Exchange and Related information
  int timeIndex = str.indexOf("U.S. Markets Closed.");
  String retTime = "";
  if (timeIndex != -1)
  {
   retTime = str.substring(timeIndex-34, timeIndex);
   retTime += " U.S. Markets Closed ";
  }
  String retVal = "";
  int dec = 0;
  int index = str.indexOf("USDGBP");
  if (index != -1)
   str = str.substring(index, str.length());
if ( (( dec = str.indexOf(".")) != -1) && (!(str.endsWith(".")))
&& Character.isDigit(str.charAt(dec+1)) )
{
  String front = "";
  int find = dec-1;
  while (Character.isDigit(str.charAt(find)))
  {
    front += str.charAt(find);
    find--;
  }
  retVal += new StringBuffer(front).reverse().toString();
  retVal += ".";
  String back = "";
  int bind = dec+4;
  while (Character.isDigit(str.charAt(bind)))
  {
   back += str.charAt(bind);
   bind--;
  }
  retVal += new StringBuffer(back).reverse().toString();
}
System.out.println(retVal);
return "USD/GBP " + retVal + " at " + retTime ;
}
String getViaHttpConnection(String url) throws IOException {
     HttpConnection c = null;
     InputStream is = null;
     StringBuffer str = new StringBuffer();
     try {
       c = (HttpConnection)Connector.open(url);
       // Get the ContentType
       String type = c.getType();
       // Getting the InputStream will open the connection
       // and read the HTTP headers. They are stored until
       // requested.
       is = c.openInputStream();

       // Get the length and process the data
       int len = (int)c.getLength();
       int ch;
       while ((ch = is.read()) != -1) {
           str.append((char)ch);
         }

     } finally {
       if (is != null)
         is.close();
       if (c != null)
         c.close();
     }
// Before returning, the resultant String should be parsed to get Exchange Rate
String val = parse(str.toString());
System.out.println(val);
return val;
   }
}

貨幣值和其它相關信息不久便出現在移動設備的用戶界面上。圖 2 說明了顯示的結果 。

圖 2. 在手持設備上運行的貨幣兌換應用程序

結束語

J2ME 有一種獨特的在受約束環境中處理數據輸入/輸出的精簡方式。有了這種功能, 支持 Java 的移動配件就不再是簡單的通信設備了,而是能夠充當微型浏覽器的設備,它 可以在移動中提供重要的信息。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved