麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學院 > 開發(fā)設計 > 正文

j2me最佳聯(lián)網(wǎng)方案終結(jié)版

2019-11-18 16:17:11
字體:
供稿:網(wǎng)友
(1) .由于無線設備所能支持的網(wǎng)絡協(xié)議非常有限,僅限于HTTP,Socket,UDP等幾種協(xié)議,不同的廠家可能還支持其他網(wǎng)絡協(xié)議,但是,MIDP  
1.0規(guī)范規(guī)定,HTTP協(xié)議是必須實現(xiàn)的協(xié)議,而其他協(xié)議的實現(xiàn)都是可選的。因此,為了能在不同類型的手機上移植,我們盡量采用HTTP作為網(wǎng)絡連接的首選協(xié)議,這樣還能重用服務器端的代碼。但是,由于HTTP是一個基于文本的效率較低的協(xié)議,因此,必須仔細考慮手機和服務器端的通信內(nèi)容,盡可能地提高效率。 
  對于MIDP應用程序,應當盡量做到: 
  1.發(fā)送請求時,附加一個User-Agent頭,傳入MIDP和自身版本號,以便服務器能識別此請求來自MIDP應用程序,并且根據(jù)版本號發(fā)送相應的相應。 
 
  2.連接服務器時,顯示一個下載進度條使用戶能看到下載進度,并能隨時中斷連接。 
 
  3.由于無線網(wǎng)絡連接速度還很慢,因此有必要將某些數(shù)據(jù)緩存起來,可以存儲在內(nèi)存中,也可以放到RMS中。 
  對于服務器端而言,其輸出響應應當盡量做到: 
  1.  
明確設置Content-Length字段,以便MIDP應用程序能讀取HTTP頭并判斷自身是否有能力處理此長度的數(shù)據(jù),如果不能,可以直接關(guān)閉連接而不必繼續(xù)讀取HTTP正文。 
 
  2.  
服務器不應當發(fā)送Html內(nèi)容,因為MIDP應用程序很難解析HTML,xml雖然能夠解析,但是耗費CPU和內(nèi)存資源,因此,應當發(fā)送緊湊的二進制內(nèi)容,用DataOutputStream直接寫入并設置Content-Type為application/octet-stream。 
 
  3. 盡量不要重定向URL,這樣會導致MIDP應用程序再次連接服務器,增加了用戶的等待時間和網(wǎng)絡流量。 
 
  4.  
如果發(fā)生異常,例如請求的資源未找到,或者身份驗證失敗,通常,服務器會向瀏覽器發(fā)送一個顯示出錯的頁面,可能還包括一個用戶登錄的Form,但是,向MIDP發(fā)送錯誤頁面毫無意義,應當直接發(fā)送一個404或401錯誤,這樣MIDP應用程序就可以直接讀取HTTP頭的響應碼獲取錯誤信息而不必繼續(xù)讀取相應內(nèi)容。 
 
  5.  
由于服務器的計算能力遠遠超過手機客戶端,因此,針對不同客戶端版本發(fā)送不同響應的任務應該在服務器端完成。例如,根據(jù)客戶端傳送的User-Agent頭確定客戶端版本。這樣,低版本的客戶端不必升級也能繼續(xù)使用。 
  MIDP的聯(lián)網(wǎng)框架定義了多種協(xié)議的網(wǎng)絡連接,但是每個廠商都必須實現(xiàn)HTTP連接,在MIDP  
2.0中還增加了必須實現(xiàn)的HTTPS連接。因此,要保證MIDP應用程序能在不同廠商的手機平臺上移植,最好只使用HTTP連接。雖然HTTP是一個基于文本的效率較低的協(xié)議,但是由于使用特別廣泛,大多數(shù)服務器應用的前端都是基于HTTP的Web頁面,因此能最大限度地復用服務器端的代碼。只要控制好緩存,仍然有不錯的速度。 
  SUN的MIDP庫提供了javax.microediton.io包,能非常容易地實現(xiàn)HTTP連接。但是要注意,由于網(wǎng)絡有很大的延時,必須把聯(lián)網(wǎng)操作放入一個單獨的線程中,以避免主線程阻塞導致用戶界面停止響應。事實上,MIDP運行環(huán)境根本就不允許在主線程中操作網(wǎng)絡連接。因此,我們必須實現(xiàn)一個靈活的HTTP聯(lián)網(wǎng)模塊,能讓用戶非常直觀地看到當前上傳和下載的進度,并且能夠隨時取消連接。 
  一個完整的HTTP連接為:用戶通過某個命令發(fā)起連接請求,然后系統(tǒng)給出一個等待屏幕提示正在連接,當連接正常結(jié)束后,前進到下一個屏幕并處理下載的數(shù)據(jù)。如果連接過程出現(xiàn)異常,將給用戶提示并返回到前一個屏幕。用戶在等待過程中能夠隨時取消并返回前一個屏幕。 
  我們設計一個HttpThread線程類負責在后臺連接服務器,HttpListener接口實現(xiàn)Observer(觀察者)模式,以便HttpThread能提示觀察者下載開始、下載結(jié)束、更新進度條等。HttpListener接口如下: 
public interface HttpListener { 
  void onSetSize(int size); 
  void onFinish(byte[] data, int size); 
  void onPRogress(int percent); 
  void onError(int code, String message); 

  實現(xiàn)HttpListener接口的是繼承自Form的一個HttpWaitUI屏幕,它顯示一個進度條和一些提示信息,并允許用戶隨時中斷連接: 
public class HttpWaitUI extends Form implements CommandListener, HttpListener { 
  private Gauge gauge; 
  private Command cancel; 
  private HttpThread downloader; 
  private Displayable displayable; 
  public HttpWaitUI(String url, Displayable displayable) { 
    super("Connecting"); 
    this.gauge = new Gauge("Progress", false, 100, 0); 
    this.cancel = new Command("Cancel", Command.CANCEL, 0); 
    append(gauge); 
    addCommand(cancel); 
    setCommandListener(this); 
    downloader = new HttpThread(url, this); 
    downloader.start(); 
  } 
  public void commandAction(Command c, Displayable d) { 
    if(c==cancel) { 
        downloader.cancel(); 
        ControllerMIDlet.goBack(); 
    } 
  } 
  public void onFinish(byte[] buffer, int size) { … } 
  public void onError(int code, String message) { … } 
  public void onProgress(int percent) { … } 
  public void onSetSize(int size) { … } 

  HttpThread是負責處理Http連接的線程類,它接受一個URL和HttpListener: 
class HttpThread extends Thread { 
  private static final int MAX_LENGTH = 20 * 1024; // 20K 
  private boolean cancel = false; 
  private String url; 
  private byte[] buffer = null; 
  private HttpListener listener; 
  public HttpThread(String url, HttpListener listener) { 
    this.url = url; 
    this.listener = listener; 
  } 
  public void cancel() { cancel = true; } 

(2).  
  使用GET獲取內(nèi)容 
  我們先討論最簡單的GET請求。GET請求只需向服務器發(fā)送一個URL,然后取得服務器響應即可。在HttpThread的run()方法中實現(xiàn)如下: 
public void run() { 
  HttpConnection hc = null; 
  InputStream input = null; 
  try { 
    hc = (HttpConnection)Connector.open(url); 
    hc.setRequestMethod(HttpConnection.GET); // 默認即為GET 
    hc.setRequestProperty("User-Agent", USER_AGENT); 
    // get response code: 
    int code = hc.getResponseCode(); 
    if(code!=HttpConnection.HTTP_OK) { 
        listener.onError(code, hc.getResponseMessage()); 
        return; 
    } 
    // get size: 
    int size = (int)hc.getLength(); // 返回響應大小,或者-1如果大小無法確定 
    listener.onSetSize(size); 
    // 開始讀響應: 
    input = hc.openInputStream(); 
    int percent = 0; // percentage 
    int tmp_percent = 0; 
    int index = 0; // buffer index 
    int reads; // each byte 
    if(size!=(-1)) 
        buffer = new byte[size]; // 響應大小已知,確定緩沖區(qū)大小 
    else 
        buffer = new byte[MAX_LENGTH]; // 響應大小未知,設定一個固定大小的緩沖區(qū) 
    while(!cancel) { 
        int len = buffer.length - index; 
        len = len>128 ? 128 : len; 
        reads = input.read(buffer, index, len); 
        if(reads<=0) 
          break; 
        index += reads; 
        if(size>0) { // 更新進度 
          tmp_percent = index * 100 / size; 
          if(tmp_percent!=percent) { 
            percent = tmp_percent; 
            listener.onProgress(percent); 
          } 
        } 
    } 
    if(!cancel && input.available()>0) // 緩沖區(qū)已滿,無法繼續(xù)讀取 
        listener.onError(601, "Buffer overflow."); 
    if(!cancel) { 
        if(size!=(-1) && index!=size) 
          listener.onError(102, "Content-Length does not match."); 
        else 
          listener.onFinish(buffer, index); 
    } 
  } 
  catch(IOException ioe) { 
    listener.onError(101, "IOException: " + ioe.getMessage()); 
  } 
  finally { // 清理資源 
    if(input!=null) 
        try { input.close(); } catch(IOException ioe) {} 
    if(hc!=null) 
        try { hc.close(); } catch(IOException ioe) {} 
  } 

  當下載完畢后,HttpWaitUI就獲得了來自服務器的數(shù)據(jù),要傳遞給下一個屏幕處理,HttpWaitUI必須包含對此屏幕的引用并通過一個setData(DataInputStream  
input)方法讓下一個屏幕能非常方便地讀取數(shù)據(jù)。因此,定義一個DataHandler接口: 
public interface DataHandler { 
  void setData(DataInputStream input) throws IOException; 

  HttpWaitUI響應HttpThread的onFinish事件并調(diào)用下一個屏幕的setData方法將數(shù)據(jù)傳遞給它并顯示下一個屏幕: 
public void onFinish(byte[] buffer, int size) { 
  byte[] data = buffer; 
  if(size!=buffer.length) { 
    data = new byte[size]; 
    System.arraycopy(data, 0, buffer, 0, size); 
  } 
  DataInputStream input = null; 
  try { 
    input = new DataInputStream(new ByteArrayInputStream(data)); 
    if(displayable instanceof DataHandler) 
        ((DataHandler)displayable).setData(input); 
    else 
        System.err.println("[WARNING] Displayable object cannot handle  
data."); 
    ControllerMIDlet.replace(displayable); 
  } 
  catch(IOException ioe) { … } 

  以下載一則新聞為例,一個完整的HTTP GET請求過程如下: 
  首先,用戶通過點擊某個屏幕的命令希望閱讀指定的一則新聞,在commandAction事件中,我們初始化HttpWaitUI和顯示數(shù)據(jù)的NewsUI屏幕: 
public void commandAction(Command c, Displayable d) { 
  HttpWaitUI wait = new HttpWaitUI("http://192.168.0.1/news.do?id=1", new  
NewsUI()); 
  ControllerMIDlet.forward(wait); 

  NewsUI實現(xiàn)DataHandler接口并負責顯示下載的數(shù)據(jù): 
public class NewsUI extends Form implements DataHandler { 
  public void setData(DataInputStream input) throws IOException { 
    String title = input.readUTF(); 
    Date date = new Date(input.readLong()); 
    String text = input.readUTF(); 
    append(new StringItem("Title", title)); 
    append(new StringItem("Date", date.toString())); 
    append(text); 
  } 

  服務器端只要以String, long,  
String的順序依次寫入DataOutputStream,MIDP客戶端就可以通過DataInputStream依次取得相應的數(shù)據(jù),完全不需要解析XML之類的文本,非常高效而且方便。 
  需要獲得聯(lián)網(wǎng)數(shù)據(jù)的屏幕只需實現(xiàn)DataHandler接口,并向HttpWaitUI傳入一個URL即可復用上述代碼,無須關(guān)心如何連接網(wǎng)絡以及如何處理用戶中斷連接。 
(3). 
  使用POST發(fā)送數(shù)據(jù) 
  以POST方式發(fā)送數(shù)據(jù)主要是為了向服務器發(fā)送較大量的客戶端的數(shù)據(jù),它不受URL的長度限制。POST請求將數(shù)據(jù)以URL編碼的形式放在HTTP正文中,字段形式為fieldname=value,用&分隔每個字段。注意所有的字段都被作為字符串處理。實際上我們要做的就是模擬瀏覽器POST一個表單。以下是IE發(fā)送一個登陸表單的POST請求: 
POST http://127.0.0.1/login.do HTTP/1.0 
Accept: image/gif, image/jpeg, image/pjpeg, */* 
Accept-Language: en-us,zh-cn;q=0.5 
Content-Type: application/x-www-form-urlencoded 
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) 
Content-Length: 28 
/r/n 
username=admin&passWord=1234 
  要在MIDP應用程序中模擬瀏覽器發(fā)送這個POST請求,首先設置HttpConnection的請求方式為POST: 
hc.setRequestMethod(HttpConnection.POST); 
  然后構(gòu)造出HTTP正文: 
byte[] data = "username=admin&password=1234".getBytes(); 
  并計算正文長度,填入Content-Type和Content-Length: 
hc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); 
hc.setRequestProperty("Content-Length", String.valueOf(data.length)); 
  然后打開OutputStream將正文寫入: 
OutputStream output = hc.openOutputStream(); 
output.write(data); 
  需要注意的是,數(shù)據(jù)仍需要以URL編碼格式編碼,由于MIDP庫中沒有J2SE中與之對應的URLEncoder類,因此,需要自己動手編寫這個encode()方法,可以參考java.net.URLEncoder.java的源碼。剩下的便是讀取服務器響應,代碼與GET一致,這里就不再詳述。 
  使用multipart/form-data發(fā)送文件 
  如果要在MIDP客戶端向服務器上傳文件,我們就必須模擬一個POST  
multipart/form-data類型的請求,Content-Type必須是multipart/form-data。 
  以multipart/form-data編碼的POST請求格式與application/x-www-form-urlencoded完全不同,multipart/form-data需要首先在HTTP請求頭設置一個分隔符,例如ABCD: 
hc.setRequestProperty("Content-Type", "multipart/form-data; boundary=ABCD"); 
  然后,將每個字段用“--分隔符”分隔,最后一個“--分隔符--”表示結(jié)束。例如,要上傳一個title字段"Today"和一個文件C:/1.txt,HTTP正文如下: 
--ABCD 
Content-Disposition: form-data; name="title" 
/r/n 
Today 
--ABCD 
Content-Disposition: form-data; name="1.txt"; filename="C:/1.txt" 
Content-Type: text/plain 
/r/n 
<這里是1.txt文件的內(nèi)容> 
--ABCD-- 
/r/n 
  請注意,每一行都必須以/r/n結(jié)束,包括最后一行。如果用Sniffer程序檢測IE發(fā)送的POST請求,可以發(fā)現(xiàn)IE的分隔符類似于---------------------------7d4a6d158c9,這是IE產(chǎn)生的一個隨機數(shù),目的是防止上傳文件中出現(xiàn)分隔符導致服務器無法正確識別文件起始位置。我們可以寫一個固定的分隔符,只要足夠復雜即可。 
  發(fā)送文件的POST代碼如下: 
String[] props = ... // 字段名 
String[] values = ... // 字段值 
byte[] file = ... // 文件內(nèi)容 
String BOUNDARY = "---------------------------7d4a6d158c9"; // 分隔符 
StringBuffer sb = new StringBuffer(); 
// 發(fā)送每個字段: 
for(int i=0; i   sb = sb.append("--"); 
  sb = sb.append(BOUNDARY); 
  sb = sb.append("/r/n"); 
  sb = sb.append("Content-Disposition: form-data; name=/""+ props +  
"/"/r/n/r/n"); 
  sb = sb.append(URLEncoder.encode(values)); 
  sb = sb.append("/r/n"); 

// 發(fā)送文件: 
sb = sb.append("--"); 
sb = sb.append(BOUNDARY); 
sb = sb.append("/r/n"); 
sb = sb.append("Content-Disposition: form-data; name=/"1/";  
filename=/"1.txt/"/r/n"); 
sb = sb.append("Content-Type: application/octet-stream/r/n/r/n"); 
byte[] data = sb.toString().getBytes(); 
byte[] end_data = ("/r/n--" + BOUNDARY + "--/r/n").getBytes(); 
// 設置HTTP頭: 
hc.setRequestProperty("Content-Type", MULTIPART_FORM_DATA + "; boundary=" +  
BOUNDARY); 
hc.setRequestProperty("Content-Length", String.valueOf(data.length + file.length  
+ end_data.length)); 
// 輸出: 
output = hc.openOutputStream(); 
output.write(data); 
output.write(file); 
output.write(end_data); 
// 讀取服務器響應: 
// TODO... 
(4). 
  使用Cookie保持session 
  通常服務器使用Session來跟蹤會話。Session的簡單實現(xiàn)就是利用Cookie。當客戶端第一次連接服務器時,服務器檢測到客戶端沒有相應的Cookie字段,就發(fā)送一個包含一個識別碼的Set-Cookie字段。在此后的會話過程中,客戶端發(fā)送的請求都包含這個Cookie,因此服務器能夠識別出客戶端曾經(jīng)連接過服務器。 
  要實現(xiàn)與瀏覽器一樣的效果,MIDP應用程序必須也能識別Cookie,并在每個請求頭中包含此Cookie。 
  在處理每次連接的響應中,我們都檢查是否有Set-Cookie這個頭,如果有,則是服務器第一次發(fā)送的Session  
ID,或者服務器認為會話超時,需要重新生成一個Session ID。如果檢測到Set-Cookie頭,就將其保存,并在隨后的每次請求中附加它: 
String session = null; 
String cookie = hc.getHeaderField("Set-Cookie"); 
if(cookie!=null) { 
  int n = cookie.indexOf(';'); 
  session = cookie.substring(0, n); 

  使用Sniffer程序可以捕獲到不同的Web服務器發(fā)送的Session。WebLogic Server 7.0返回的Session如下: 
Set-Cookie:  
JSESSIONID=CXP4FMwOJB06XCByBWfwZBQ0IfkroKO2W7FZpkLbmWsnERuN5u2L!-1200402410;  
path=/ 
  而Resin 2.1返回的Session則是: 
Set-Cookie: JSESSIONID= aTMCmwe9F5j9; path=/ 
  運行asp.net的IIS返回的Session: 
Set-Cookie: ASPSESSIONIDQATSASQB=GNGEEJIDMDFCMOOFLEAKDGGP; path=/ 
  我們無須關(guān)心Session ID的內(nèi)容,服務器自己會識別它。我們只需在隨后的請求中附加上這個Session ID即可: 
if(session!=null) 
  hc.setRequestProperty("Cookie", session); 
  對于URL重寫來保持Session的方法,在PC客戶端可能很有用,但是,由于MIDP程序很難分析出URL中有用的Session信息,因此,不推薦使用這種方法。

(出處:http://www.companysz.com)



發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 精品久久久91 | 一级免费 | 一级观看免费完整版视频 | 国产69精品久久久久9999不卡免费 | 色999国产 | 欧美18—19sex性hd按摩 | 一级黄色电影网站 | 视频一区二区在线播放 | 日本高清com | 久久久av影视 | 久久久久久久免费精品 | 黄色av网站在线观看 | 中文字幕一二区 | 国产一区二区免费在线观看 | 精品亚洲在线 | 国产一精品久久99无吗一高潮 | 日韩中文字幕一区二区三区 | 一级黄色欧美 | 看片一区二区三区 | 日本成人一区二区 | 羞羞视频免费网站含羞草 | 九九热视频免费观看 | 一本色道久久99精品综合蜜臀 | 国产噜噜噜噜久久久久久久久 | 久久久久久久国产视频 | 久久一区国产 | 中文字幕在线成人 | 国产成年人网站 | 日本不卡二区 | 欧美成人精品一区 | 欧美亚洲免费 | 成人激情视频网站 | 久久久久久久久久91 | 福利在线影院 | 黄色va视频| 久久99精品国产99久久6男男 | 黄污网站在线 | 一区二区三区黄色 | 国产在线播放一区二区 | 自拍偷拍亚洲图片 | 亚洲精品自在在线观看 |