• 封装MIDP 1.0 HttpConnection用于商业应用[javaME]


    另外,还有一篇必读的文章《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,算是另外一种封装实现了。

    一个来自日本的MIDP 1.0 HttpConnection类的robust封装

    作者:zhengyun_ustc、cleverpig



    一、“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定义


    不知道大家会更喜欢哪一种封装呢?


    HttpConnectionWrapper吗?
    他的调用方法:


            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?
    他的调用方法:

    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 {

  • 相关阅读:
    【学习笔记】最小表示法
    bzoj1912【Apio2010】patrol 巡逻
    hdu1057
    hdu1056
    hdu1055
    hdu1054
    hdu1053
    hdu1052
    hdu1051
    hdu1050
  • 原文地址:https://www.cnblogs.com/zhengyun_ustc/p/NetConnection.html
Copyright © 2020-2023  润新知