讓變化成為計(jì)劃的一部分

          歡迎大家探討本Blog涉及的所有軟件課題。我的Google Talk ID:zhengyun(at)gmail.com。

          我最希望軟件帶給用戶的感受是:美好的體驗(yàn)、舒適感、簡(jiǎn)約、干凈...

          posts - 32, comments - 8, trackbacks - 0, articles - 0
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          另外,還有一篇必讀的文章《Debugging MIDP HTTP Requests,http://developers.sun.com/techtopics/mobility/midp/articles/httpdebug/》,也給出了一份源代碼,http://developers.sun.com/techtopics/mobility/midp/articles/httpdebug/src/httpwrapper.zip,算是另外一種封裝實(shí)現(xiàn)了。

          一個(gè)來自日本的MIDP 1.0 HttpConnection類的robust封裝

          作者:zhengyun_ustc、cleverpig



          一、“NetConnection”簡(jiǎn)介:

          轉(zhuǎn)述Matrix上zhengyun_ustc所述:“你的HttpConnection是否封裝的足夠健壯呢?遇到各種情況,你是否有信心應(yīng)對(duì)呢?譬如說,你要請(qǐng)求的Response包實(shí)在太大,以至于運(yùn)營(yíng)商給你掐了告訴你說超時(shí);譬如說你是不是總要自己寫一個(gè)線程來專門作http連接?譬如說有一些移動(dòng)運(yùn)營(yíng)商設(shè)置了caching proxy servers,妨礙了你的測(cè)試。”

          為了解決這個(gè)問題,一位日本程序員“JAY-F”針對(duì)MIDP1.0提供了一種robust的“NetConnection”封裝。這個(gè)HttpConnnection類負(fù)責(zé)管理連接并易于使用。

          二、“NetConnection”特性:

          1. 跨過Proxy-server阻礙:

          一些移動(dòng)網(wǎng)絡(luò)放置了代理服務(wù)器用來提高訪問速度,但是它的cache也成為了開發(fā)人員測(cè)試/調(diào)試程序的一大障礙。“NetConnection”類使用一個(gè)簡(jiǎn)單的http request屬性將server上的代理功能關(guān)閉掉。

          2. 使用線程分離的連接模式:

          本類可以使用單線程、多線程兩種模式運(yùn)行,只要設(shè)置一個(gè)簡(jiǎn)單的標(biāo)志即可。

          3. 支持Http request range:

          由于服務(wù)商在其網(wǎng)絡(luò)上可能存在一些針對(duì)回應(yīng)數(shù)據(jù)最大長(zhǎng)度的限制,所以“NetConnection”類提供了構(gòu)造request URL的功能使回應(yīng)數(shù)據(jù)分為多個(gè)數(shù)據(jù)包。從而去除了前面的限制。

          三、netConnection是如何實(shí)現(xiàn)的?

          1。netConnection類結(jié)構(gòu)分析:

          此類實(shí)現(xiàn)了Runnable接口,其運(yùn)行模式支持多線程模式:當(dāng)前只能由一個(gè)線程使用資源,其它線程wait。

          此類使用了一些靜態(tài)成員變量:

                  //當(dāng)前只能由一個(gè)線程使用singleton。
                  private static NetConnection singleton = new NetConnection();

                  private static HttpConnection httpConn;

                  private static String url;

                  private static String method;

                  private static byte[] data;
                          

                  private static String contentType;
                  

                  private static long lowRange;
                  

                  private static long highRange;
                  

                  private static boolean disableProxy;
                  

                  private static boolean detached;
                  
                  private static byte[] response;


          類方法:

          //線程run方法
          public void run()

          //當(dāng)前運(yùn)行的線程執(zhí)行完畢后,通報(bào)給其它的由于等待資源而wait狀態(tài)的線程
          private synchronized void forceNotify()

          //當(dāng)資源正在被其它線程使用時(shí),當(dāng)前線程進(jìn)入wait狀態(tài)
          private synchronized void forceWait()

          //關(guān)閉http連接
          private static void severConnection()


          由于使用了這些static成員變量,所以一些操作方法需要同步(synchronized)。

          2。netConnection核心代碼解析:

          netConnection類的實(shí)現(xiàn)思想很簡(jiǎn)單,就是設(shè)置一些request屬性和對(duì)于GET方法構(gòu)造一個(gè)特殊的URL。更重要的是其作者對(duì)http協(xié)議的深入理解、嚴(yán)謹(jǐn)?shù)拇a風(fēng)格值得吾輩學(xué)習(xí)、研究。這也是本人分析其核心代碼的一大原因。

          /**
          * 實(shí)現(xiàn)了連接邏輯。
          * 調(diào)用者可以在分離的線程中使用netConnection類的靜態(tài)連接。
          * @throws IllegalStateException 如果此方法直接其它類調(diào)用則拋出該異常
          */
          public void run() {
                  
                  if (url == null) {
                          throw new IllegalStateException("Cannot invoke this method!");
                  }

                  
                  DataOutputStream dos = null;
                  DataInputStream dis = null;
                  StringBuffer buffer = null;

                  try {

                          int permissions = 0;
                          
                          //根據(jù)method值,設(shè)置Connector的權(quán)限(READ/READ_WRITE)
                          if (HttpConnection.GET.equals(method)) {
                                  permissions = Connector.READ;
                          } else if (HttpConnection.POST.equals(method)) {
                                  permissions = Connector.READ_WRITE;
                          }
                          
                          //如果關(guān)閉server代理功能,則構(gòu)造noProxyUrl。
                          //原理:使用timestamp作為該URL中no-proxy參數(shù)值,
                          //        致使server視其為client發(fā)來的新請(qǐng)求。
                          if (disableProxy) {
                                  
                                  boolean hasQueryParams = false;
                                  
                                  char[] ca = url.toCharArray();
                                  //判斷原URL中是否含有參數(shù)
                                  for (int loop = 0; loop < url.length(); loop++) {
                                          
                                          if (ca[loop] == '?') {
                                                  hasQueryParams = true;
                                                  break;
                                          }
                                  }
                                  
                                  //由于需要多次字符串拼接,所以使用可提供效率的StringBuffer類
                                  StringBuffer noProxyUrl = new StringBuffer();

                                  //將原URL內(nèi)容復(fù)制到noProxyUrl
                                  noProxyUrl.append(url);

                                  //如果原URL中含有參數(shù),
                                  //  則需要在noProxyUrl中增加"&",
                                  //  否則直接在noProxyUrl中增加"?",
                                  //  這樣做為了后面增加no-proxy參數(shù)做準(zhǔn)備。
                                  if (hasQueryParams) {
                                          noProxyUrl.append("&");
                                  } else {
                                          noProxyUrl.append("?");
                                  }

                                  //增加no-proxy參數(shù)
                                  noProxyUrl.append("no-proxy=");
                                  noProxyUrl.append(System.currentTimeMillis()); // timestamp
                                  
                                  //將構(gòu)造好的noProxyUrl復(fù)制到原URL
                                  url = noProxyUrl.toString();
                          }
                          
                          

                          // 打開Http 連接
                          httpConn = (HttpConnection) Connector.open(url, permissions, true);
                          //設(shè)置request方法
                          httpConn.setRequestMethod(method);

                          //如果request權(quán)限為READ(即request方法為GET),
                          //則需要設(shè)置http request屬性的Range。
                          //原理:設(shè)置http request屬性的Range后的,
                          //        server接收到該request后將把response數(shù)據(jù)分成小部分發(fā)回。
                          //        從而避免了部分運(yùn)營(yíng)商對(duì)http response size的限制。
                          if (permissions == Connector.READ) {        
                                  if (lowRange > -1 && lowRange < highRange) {
                                          StringBuffer range = new StringBuffer();
                                          
                                          range.append("bytes=");
                                          range.append(lowRange);
                                          range.append("-");
                                          range.append(highRange);
                                          
                                          httpConn.setRequestProperty("Range", range.toString());
                                  }
                          //否則,request權(quán)限為READ_WRITE(即request方法為POST),
                          //那么設(shè)置request的Content-Type屬性。
                          } else if (permissions == Connector.READ_WRITE) {
                                  // POST request
                                  httpConn.setRequestProperty("Content-Type", contentType);
                                  dos = httpConn.openDataOutputStream();
                                  dos.write(data);
                          }
                  
                  } catch (Exception e) {
                  
                          exceptionPipe = e;
                          //如果程序運(yùn)行在多線程模式,則在異常發(fā)生后需要喚醒其它睡眠的線程繼續(xù)run
                          if (detached) {
                                  forceNotify();
                          }
                          
                          return;
                          
                  } finally {

                          try {
                                  try {
                                          if (dos != null) {
                                                  // 關(guān)閉dos
                                                  dos.close();
                                          }
                                  } catch (Exception e) {
                                          // 如果程序運(yùn)行在多線程模式,則在異常發(fā)生后需要喚醒其它睡眠的線程繼續(xù)run
                                          if (exceptionPipe == null) {
                                                  exceptionPipe = e;
                                                  
                                                  if (detached) {
                                                          forceNotify();
                                                  }
                                                  return;
                                          }
                                  } finally {
                                          dos = null;
                                  }
                                  
                                  // 讀取http連接的回應(yīng)代碼
                                  int responseCode = httpConn.getResponseCode();
                                  
                                  //當(dāng)request方法為GET,并設(shè)置了request range時(shí),接收到的回應(yīng)代碼為HTTP_PARTIAL
                                  //當(dāng)request方法為POST,接收到的回應(yīng)代碼為HTTP_OK
                                  //如果上述兩種回應(yīng)代碼均沒有收到,則表明連接失敗或者出問題
                                  if (responseCode != HttpConnection.HTTP_OK
                                                  && responseCode != HttpConnection.HTTP_PARTIAL) {

                                          if (exceptionPipe == null) {
                                                  StringBuffer errorCode = new StringBuffer();
                                                  errorCode.append("Response code from server: ");
                                                  errorCode.append(responseCode);
                                                  errorCode.append("\nMessage: [");
                                                  errorCode.append(httpConn.getResponseMessage());
                                                  errorCode.append("]");
                                                  
                                                  exceptionPipe = new IOException(errorCode.toString());
                                                  
                                                  if (detached) {
                                                          forceNotify();
                                                  }
                                                  return;
                                          }
                                  }

                                  //如果收到了上述的兩種回應(yīng)代碼之一,則可以繼續(xù)讀取server的response數(shù)據(jù)
                                  dis = httpConn.openDataInputStream();

                                  //循環(huán)讀取repsonse數(shù)據(jù)
                                  int ch;
                                  buffer = new StringBuffer();
                          while ((ch = dis.read()) != -1) {
                                  buffer.append((char) ch);
                          }

                          //將response數(shù)據(jù)進(jìn)行必要的編碼轉(zhuǎn)換                
                                  response = buffer.toString().getBytes("ISO8859_1");
                                  //接收到回應(yīng)后,表明整個(gè)http會(huì)話過程結(jié)束,線程將結(jié)束。
                                  //如果程序運(yùn)行在多線程模式,則此時(shí)需要喚醒其它睡眠的線程繼續(xù)run
                                  if (detached) {
                                          forceNotify();
                                  }
                                  
                                  return;

                          } catch (Exception e) {
                                  
                                  if (exceptionPipe == null) {
                                          exceptionPipe = e;
                                          
                                          if (detached) {
                                                  forceNotify();
                                          }
                                          
                                          return;
                                  }
                          } finally {
                              
                                  try {
                                          if (dis != null) {
                                                  // 關(guān)閉dis
                                                  dis.close();
                                          }
                                  } catch (Exception e) {
                                          // 若關(guān)閉dis時(shí)發(fā)生異常,則進(jìn)行異常處理
                                          if (exceptionPipe == null) {
                                                  exceptionPipe = e;
                                                  
                                                  if (detached) {
                                                          forceNotify();
                                                  }
                                                  return;
                                          }
                                  } finally {
                                          dis = null;
                                  }
                                  
                                  try {
                                          if (httpConn != null) {
                                                  //關(guān)閉http連接
                                                  httpConn.close();

                                                  httpConn = null;
                                          }
                                  } catch (Exception e) {

                                          if (exceptionPipe == null) {
                                                  exceptionPipe = e;
                                                  
                                                  if (detached) {
                                                          forceNotify();
                                                  }
                                                  return;
                                          }
                                  }
                          }
                  }
          }


          五、參考資料:

          聯(lián)系netConnection作者:JAY-F
          源代碼下載
          HTTP/1.1定義


          不知道大家會(huì)更喜歡哪一種封裝呢?


          HttpConnectionWrapper嗎?
          他的調(diào)用方法:


                  Wait w = (Wait) display.getCurrent();
                  HttpConnection conn = null;
                  InputStream in = null;
                  
                  try {
                      conn = new HttpConnectionWrapper( (HttpConnection) Connector.open( url ) );
                      conn.setRequestProperty( "User-Agent", "Profile/MIDP-1.0 Configuration/CLDC-1.0" );
                      conn.setRequestProperty( "Connection", "close" );
                      conn.setRequestProperty( "Send-HTTP-Log-To", "ericgiguere@ericgiguere.com" );
                      int rc = conn.getResponseCode();
                      w.update( "Response code " + rc );
                      in = conn.openInputStream();
                      
                      for( int i = 0; i < 100; ++i ){
                          if( in.read() == -1 ) break;
                      }


          封裝類示意:


          /**
           * A wrapper for the HttpConnection interface that logs method
           * calls and state transitions. Wrap a connection immediately
           * after obtaining it from Connector.open. Information is logged
           * according to the log level set the "httpwrapper" logger.
           */

          public class HttpConnectionWrapper implements HttpConnection {



          還是NetConnection?
          他的調(diào)用方法:

          NetConnection.connect("http://www.molon.com.cn/",data,HttpConnection.GET,...);


          封裝類示意:


          /**
           * This class provides robust network connectivity and exception handling
           * over an unreliable MIDP HttpConnection.
           *
           * In addition the caller may perform a combination of any of the below
           * functions.
           *
           * - Proxy-server thwarting
           * - HTTP range requests
           * - Thread-separated connections
           *
           * @author Jason Fuerstenberg (http://www.jay-f.jp)
           * @version 2004/03/15
           */
          public final class NetConnection implements Runnable {

          主站蜘蛛池模板: 宁强县| 叙永县| 佛山市| 清苑县| 故城县| 宜章县| 民县| 同江市| 丹棱县| 金华市| 金阳县| 云南省| 建瓯市| 邹平县| 东阿县| 嵩明县| 洛隆县| 西城区| 广西| 泽库县| 色达县| 岳阳县| 汝阳县| 聊城市| 通榆县| 扎赉特旗| 远安县| 江都市| 斗六市| 兴宁市| 太仓市| 阿克陶县| 环江| 霍山县| 苗栗县| 台前县| 吉隆县| 佛教| 长泰县| 巨野县| 丰顺县|