分享
 
 
 

MIDP 1.0 HttpConnection类的robust封装

王朝other·作者佚名  2008-05-31
窄屏简体版  字體: |||超大  

一、“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.knowsky.com)

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有