WEB开发网      濠电姷鏁告繛鈧繛浣冲洤纾瑰┑鐘宠壘閻ょ偓銇勯幇鍫曟闁稿鍠愰妵鍕冀閵娧佲偓鎺楁⒒閸曨偄顏柡宀嬬畱铻e〒姘煎灡绗戦梻浣筋嚙濮橈箓顢氳濠€浣糕攽閻樿宸ュΔ鐘叉啞缁傚秹宕滆绾惧ジ寮堕崼娑樺缂佹宀搁弻鐔风暋閻楀牆娈楅梺璇″枓閺呯姴鐣疯ぐ鎺濇晝闁靛牆妫欓蹇旂節閻㈤潧浠﹂柛銊ョ埣楠炴劙骞橀鑲╋紱闂佽宕樼粔顔裤亹閹烘挸浜归梺缁樺灦閿曗晛螞閸曨垱鈷戦柟鑲╁仜婵″ジ鎮楀☉鎺撴珖缂侇喖顑呴鍏煎緞濡粯娅囬梻浣瑰缁诲倿寮绘繝鍥ㄦ櫇闁稿本绋撻崢鐢告煟鎼淬垻鈯曢柨姘舵煟韫囥儳绋荤紒缁樼箖缁绘繈宕橀妸褌绱濋梻浣筋嚃閸ㄤ即宕弶鎴犳殾闁绘梻鈷堥弫鍌炴煕閳锯偓閺呮瑧妲愬Ο琛℃斀闁绘劕妯婇崵鐔封攽椤旇棄鍔ら摶鐐烘煕閺囥劌澧柛娆忕箻閺屽秹宕崟顒€娅g紓浣插亾濠㈣泛顑囩粻楣冩煙鐎涙ḿ绠橀柨娑樼У椤ㄣ儵鎮欓鍕紙闂佽鍠栫紞濠傜暦閹偊妲诲┑鈩冨絻椤兘寮诲☉銏犖╅柕澶堝労閸斿绱撴担绋库偓鍝ョ矓瑜版帒鏋侀柟鍓х帛閺呮悂鏌ㄩ悤鍌涘 ---闂傚倸鍊烽悞锔锯偓绗涘厾娲煛閸涱厾顔嗛梺璺ㄥ櫐閹凤拷
开发学院软件开发Java MIDP 1.0 HttpConnection类的robust封装 阅读

MIDP 1.0 HttpConnection类的robust封装

 2007-12-23 12:29:29 来源:WEB开发网 闂傚倸鍊风欢姘缚瑜嶈灋闁圭虎鍠栫粻顖炴煥閻曞倹瀚�闂傚倸鍊风粈渚€骞夐敓鐘插瀭闁汇垹鐏氬畷鏌ユ煙閹殿喖顣奸柛搴$У閵囧嫰骞掗幋婵冨亾閻㈢ǹ纾婚柟鐐灱濡插牊绻涢崱妤冃℃繛宀婁簽缁辨捇宕掑鎵佹瀸闂佺懓鍤栭幏锟�濠电姷鏁告慨顓㈠箯閸愵喖宸濇い鎾寸箘閹规洟姊绘笟鈧ḿ褍煤閵堝悿娲Ω閳轰胶鍔﹀銈嗗笂閼冲爼鍩婇弴銏$厪闁搞儮鏅涙禒褏绱掓潏鈺佷槐闁轰焦鎹囬弫鎾绘晸閿燂拷闂傚倸鍊风欢姘缚瑜嶈灋闁圭虎鍠栫粻顖炴煥閻曞倹瀚�  闂傚倸鍊烽懗鑸电仚缂備胶绮〃鍛村煝瀹ュ鍗抽柕蹇曞У閻庮剟姊虹紒妯哄闁诲繑姘ㄩ埀顒佸嚬閸撶喎顫忓ú顏勫瀭妞ゆ洖鎳庨崜浼存⒑闁偛鑻晶顔剧磼婢跺﹦绉虹€殿喖顭锋俊姝岊槷闁稿鎹囧Λ鍐ㄢ槈濞嗗繑娈橀梻浣风串缂嶁偓濞存粠鍓熼崺鈧い鎺戝€归弳顒勬煕鐎n亷韬€规洑鍗冲鍊燁槾闁哄棴绠撻弻銊╂偆閸屾稑顏�
核心提示:一、“NetConnection”简介:转述Matrix上zhengyun_ustc所述:“你的HttpConnection是否封装的足够健壮呢?遇到各种情况,你是否有信心应对呢?譬如说,MIDP 1.0 HttpConnection类的robust封装,你要请求的Response包实在太大,以至于运营商给你掐了告诉你

  一、“NetConnection”简介:

转述Matrix上zhengyun_ustc所述:“你的HttpConnection是否封装的足够健壮呢?遇到各种情况,你是否有信心应对呢?譬如说,你要请求的Response包实在太大,以至于运营商给你掐了告诉你说超时;譬如说你是不是总要自己写一个线程来专门作http连接?譬如说有一些移动运营商设置了caching PRoxy servers,妨碍了你的测试。”

为了解决这个问题,一位日本程序员“JAY-F”针对MIDP1.0提供了一种robust的“NetConnection”封装。这个HttpConnnection类负责管理连接并易于使用。

二、“NetConnection”特性:

1. 跨过Proxy-server阻碍:

一些移动网络放置了代理服务器用来提高访问速度,但是它的cache也成为了开发人员测试/调试程序的一大障碍。“NetConnection”类使用一个简单的http request属性将server上的代理功能关闭掉。

2. 使用线程分离的连接模式:

本类可以使用单线程、多线程两种模式运行,只要设置一个简单的标志即可。

3. 支持Http request range:

由于服务商在其网络上可能存在一些针对回应数据最大长度的限制,所以“NetConnection”类提供了构造request URL的功能使回应数据分为多个数据包。从而去除了前面的限制。

三、netConnection是如何实现的?

1。netConnection类结构分析:

此类实现了Runnable接口,其运行模式支持多线程模式:当前只能由一个线程使用资源,其它线程wait。

此类使用了一些静态成员变量:

    //当前只能由一个线程使用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()

//当前运行的线程执行完毕后,通报给其它的由于等待资源而wait状态的线程
private synchronized void forceNotify()

//当资源正在被其它线程使用时,当前线程进入wait状态
private synchronized void forceWait()

//关闭http连接
private static void severConnection()


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

2。netConnection核心代码解析:

netConnection类的实现思想很简单,就是设置一些request属性和对于GET方法构造一个特殊的URL。更重要的是其作者对http协议的深入理解、严谨的代码风格值得吾辈学习、研究。这也是本人分析其核心代码的一大原因。

/**
* 实现了连接逻辑。
* 调用者可以在分离的线程中使用netConnection类的静态连接。
* @throws IllegalStateException 如果此方法直接其它类调用则抛出该异常
*/
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;
        
        //根据method值,设置Connector的权限(READ/READ_WRITE)
        if (HttpConnection.GET.equals(method)) {
            permissions = Connector.READ;
        } else if (HttpConnection.POST.equals(method)) {
            permissions = Connector.READ_WRITE;
        }
        
        //如果关闭server代理功能,则构造noProxyUrl。
        //原理:使用timestamp作为该URL中no-proxy参数值,
        //    致使server视其为client发来的新请求。
        if (disableProxy) {
            
            boolean hasQueryParams = false;
            
            char[] ca = url.toCharArray();
            //判断原URL中是否含有参数
            for (int loop = 0; loop < url.length(); loop++) {
                
                if (ca[loop] == '?') {
                    hasQueryParams = true;
                    break;
                }
            }
            
            //由于需要多次字符串拼接,所以使用可提供效率的StringBuffer类
            StringBuffer noProxyUrl = new StringBuffer();

            //将原URL内容复制到noProxyUrl
            noProxyUrl.append(url);

            //如果原URL中含有参数,
            // 则需要在noProxyUrl中增加"&",
            // 否则直接在noProxyUrl中增加"?",
            // 这样做为了后面增加no-proxy参数做准备。
            if (hasQueryParams) {
                noProxyUrl.append("&");
            } else {
                noProxyUrl.append("?");
            }

            //增加no-proxy参数
            noProxyUrl.append("no-proxy=");
            noProxyUrl.append(System.currentTimeMillis()); // timestamp
            
            //将构造好的noProxyUrl复制到原URL
            url = noProxyUrl.toString();
        }
        
        

        // 打开Http 连接
        httpConn = (HttpConnection) Connector.open(url, permissions, true);
        //设置request方法
        httpConn.setRequestMethod(method);

        //如果request权限为READ(即request方法为GET),
        //则需要设置http request属性的Range。
        //原理:设置http request属性的Range后的,
        //    server接收到该request后将把response数据分成小部分发回。
        //    从而避免了部分运营商对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权限为READ_WRITE(即request方法为POST),
        //那么设置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;
        //如果程序运行在多线程模式,则在异常发生后需要唤醒其它睡眠的线程继续run
        if (detached) {
            forceNotify();
        }
        
        return;
        
    } finally {

        try {
            try {
                if (dos != null) {
                    // 关闭dos
                    dos.close();
                }
            } catch (Exception e) {
                // 如果程序运行在多线程模式,则在异常发生后需要唤醒其它睡眠的线程继续run
                if (exceptionPipe == null) {
                    exceptionPipe = e;
                    
                    if (detached) {
                        forceNotify();
                    }
                    return;
                }
            } finally {
                dos = null;
            }
            
            // 读取http连接的回应代码
            int responseCode = httpConn.getResponseCode();
            
            //当request方法为GET,并设置了request range时,接收到的回应代码为HTTP_PARTIAL
            //当request方法为POST,接收到的回应代码为HTTP_OK
            //如果上述两种回应代码均没有收到,则表明连接失败或者出问题
            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;
                }
            }

            //如果收到了上述的两种回应代码之一,则可以继续读取server的response数据
            dis = httpConn.openDataInputStream();

            //循环读取repsonse数据
            int ch;
            buffer = new StringBuffer();
        while ((ch = dis.read()) != -1) {
            buffer.append((char) ch);
        }

        //将response数据进行必要的编码转换        
            response = buffer.toString().getBytes("ISO8859_1");
            //接收到回应后,表明整个http会话过程结束,线程将结束。
            //如果程序运行在多线程模式,则此时需要唤醒其它睡眠的线程继续run
            if (detached) {
                forceNotify();
            }
            
            return;

        } catch (Exception e) {
            
            if (exceptionPipe == null) {
                exceptionPipe = e;
                
                if (detached) {
                    forceNotify();
                }
                
                return;
            }
        } finally {
          
            try {
                if (dis != null) {
                    // 关闭dis
                    dis.close();
                }
            } catch (Exception e) {
                // 若关闭dis时发生异常,则进行异常处理
                if (exceptionPipe == null) {
                    exceptionPipe = e;
                    
                    if (detached) {
                        forceNotify();
                    }
                    return;
                }
            } finally {
                dis = null;
            }
            
            try {
                if (httpConn != null) {
                    //关闭http连接
                    httpConn.close();

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

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


五、参考资料:

联系netConnection作者:JAY-F
源代码下载
HTTP/1.1定义

(出处:http://www.cncms.com)


Tags:MIDP HttpConnection robust

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接