posts - 33,comments - 21,trackbacks - 0

          一、“NetConnection”簡(jiǎn)介:
          轉(zhuǎn)述Matrix上zhengyun_ustc所述:“你的HttpConnection是否封裝的足夠健壯呢?遇到各種情況,你是否有信心應(yīng)對(duì)呢?譬如說(shuō),你要請(qǐng)求的Response包實(shí)在太大,以至于運(yùn)營(yíng)商給你掐了告訴你說(shuō)超時(shí);譬如說(shuō)你是不是總要自己寫一個(gè)線程來(lái)專門作http連接?譬如說(shuō)有一些移動(dòng)運(yùn)營(yíng)商設(shè)置了caching proxy servers,妨礙了你的測(cè)試。”
          為了解決這個(gè)問(wèn)題,一位日本程序員“JAY-F”針對(duì)MIDP1.0提供了一種robust的“NetConnection”封裝。這個(gè)HttpConnnection類負(fù)責(zé)管理連接并易于使用。
          二、“NetConnection”特性:
          1. 跨過(guò)Proxy-server阻礙:
          一些移動(dòng)網(wǎng)絡(luò)放置了代理服務(wù)器用來(lái)提高訪問(wèn)速度,但是它的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ā)來(lái)的新請(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)代碼均沒(méi)有收到,則表明連接失敗或者出問(wèn)題
          ????????????????????????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ì)話過(guò)程結(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定義
          posted on 2007-03-17 18:00 英明 閱讀(1245) 評(píng)論(0)  編輯  收藏 所屬分類: J2ME
          主站蜘蛛池模板: 杂多县| 青田县| 洪泽县| 开原市| 乌鲁木齐县| 繁峙县| 海安县| 泰和县| 东至县| 泰宁县| 阳高县| 六枝特区| 仪征市| 手游| 贵南县| 南召县| 西乌珠穆沁旗| 稷山县| 紫阳县| 阳谷县| 汽车| 江西省| 普兰县| 乳源| 霞浦县| 东方市| 桃园市| 抚松县| 武平县| 惠东县| 色达县| 石渠县| 新化县| 宾阳县| 会昌县| 白山市| 安多县| 同心县| 祁东县| 合肥市| 浪卡子县|