H5W3
当前位置:H5W3 > 其他技术问题 > 正文

MIDP 1.0 HttpConnection类的robust封装

一、“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;                                }                        }                }        }}

本文地址:H5W3 » MIDP 1.0 HttpConnection类的robust封装

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址