一
NetConnection
简介
转述Matrix上zhengyun_ustc所述你的HttpConnection是否封装的足够健壮呢?遇到各种情况你是否有信心应对呢?譬如说你要请求的Response包实在太大以至于运营商给你掐了告诉你说超时譬如说你是不是总要自己写一个线程来专门作http连接?譬如说有一些移动运营商设置了caching proxy servers妨碍了你的测试
为了解决这个问题一位日本程序员JAYF针对MIDP提供了一种robust的NetConnection封装这个HttpConnnection类负责管理连接并易于使用
二NetConnection特性
跨过Proxyserver阻碍
一些移动网络放置了代理服务器用来提高访问速度但是它的cache也成为了开发人员测试/调试程序的一大障碍NetConnection类使用一个简单的http request属性将server上的代理功能关闭掉
使用线程分离的连接模式
本类可以使用单线程多线程两种模式运行只要设置一个简单的标志即可
支持Http request range
由于服务商在其网络上可能存在一些针对回应数据最大长度的限制所以NetConnection类提供了构造request URL的功能使回应数据分为多个数据包从而去除了前面的限制
三netConnection是如何实现的?
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)
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 = ;
//根据method值设置Connector的权限(READ/READ_WRITE)
if (HttpConnectionGETequals(method)) {
permissions = ConnectorREAD;
} else if (HttpConnectionPOSTequals(method)) {
permissions = ConnectorREAD_WRITE;
}
//如果关闭server代理功能则构造noProxyUrl
//原理使用timestamp作为该URL中noproxy参数值
//致使server视其为client发来的新请求
if (disableProxy) {
boolean hasQueryParams = false;
char[] ca = urltoCharArray();
//判断原URL中是否含有参数
for (int loop = ; loop < urllength(); loop++) {
if (ca[loop] == ?) {
hasQueryParams = true;
break;
}
}
//由于需要多次字符串拼接所以使用可提供效率的StringBuffer类
StringBuffer noProxyUrl = new StringBuffer();
//将原URL内容复制到noProxyUrl
noProxyUrlappend(url);
//如果原URL中含有参数
//则需要在noProxyUrl中增加&
//否则直接在noProxyUrl中增加?
//这样做为了后面增加noproxy参数做准备
if (hasQueryParams) {
noProxyUrlappend(&);
} else {
noProxyUrlappend(?);
}
//增加noproxy参数
noProxyUrlappend(noproxy=);
noProxyUrlappend(SystemcurrentTimeMillis()); // timestamp
//将构造好的noProxyUrl复制到原URL
url = noProxyUrltoString();
}
// 打开Http 连接
httpConn = (HttpConnection) Connectoropen(url permissions true);
//设置request方法
(method);
//如果request权限为READ(即request方法为GET)
//则需要设置http request属性的Range
//原理设置http request属性的Range后的
//server接收到该request后将把response数据分成小部分发回
//从而避免了部分运营商对http response size的限制
if (permissions == ConnectorREAD) {
if (lowRange > && lowRange < highRange) {
StringBuffer range = new StringBuffer();
rangeappend(bytes=);
rangeappend(lowRange);
rangeappend();
rangeappend(highRange);
(Range rangetoString());
}
//否则request权限为READ_WRITE(即request方法为POST)
//那么设置request的ContentType属性
} else if (permissions == ConnectorREAD_WRITE) {
// POST request
(ContentType contentType);
dos = ();
doswrite(data);
}
} catch (Exception e) {
exceptionPipe = e;
//如果程序运行在多线程模式则在异常发生后需要唤醒其它睡眠的线程继续run
if (detached) {
forceNotify();
}
return;
} finally {
try {
try {
if (dos != null) {
// 关闭dos
dosclose();
}
} catch (Exception e) {
// 如果程序运行在多线程模式则在异常发生后需要唤醒其它睡眠的线程继续run
if (exceptionPipe == null) {
exceptionPipe = e;
if (detached) {
forceNotify();
}
return;
}
} finally {
dos = null;
}
// 读取http连接的回应代码
int responseCode = ();
//当request方法为GET并设置了request range时接收到的回应代码为HTTP_PARTIAL
//当request方法为POST接收到的回应代码为HTTP_OK
//如果上述两种回应代码均没有收到则表明连接失败或者出问题
if (responseCode != HttpConnectionHTTP_OK
&& responseCode != HttpConnectionHTTP_PARTIAL) {
if (exceptionPipe == null) {
StringBuffer errorCode = new StringBuffer();
errorCodeappend(Response code from server: );
errorCodeappend(responseCode);
errorCodeappend(\nMessage: [);
errorCodeappend(());
errorCodeappend(]);
exceptionPipe = new IOException(errorCodetoString());
if (detached) {
forceNotify();
}
return;
}
}
//如果收到了上述的两种回应代码之一则可以继续读取server的response数据
dis = ();
//循环读取repsonse数据
int ch;
buffer = new StringBuffer();
while ((ch = disread()) != ) {
bufferappend((char) ch);
}
//将response数据进行必要的编码转换
response = buffertoString()getBytes(ISO_);
//接收到回应后表明整个http会话过程结束线程将结束
//如果程序运行在多线程模式则此时需要唤醒其它睡眠的线程继续run
if (detached) {
forceNotify();
}
return;
} catch (Exception e) {
if (exceptionPipe == null) {
exceptionPipe = e;
if (detached) {
forceNotify();
}
return;
}
} finally {
try {
if (dis != null) {
// 关闭dis
disclose();
}
} catch (Exception e) {
// 若关闭dis时发生异常则进行异常处理
if (exceptionPipe == null) {
exceptionPipe = e;
if (detached) {
forceNotify();
}
return;
}
} finally {
dis = null;
}
try {
if (httpConn != null) {
//关闭http连接
();
httpConn = null;
}
} catch (Exception e) {
if (exceptionPipe == null) {
exceptionPipe = e;
if (detached) {
forceNotify();
}
return;
}
}
}
}
}