到目前从事安卓应用开发的经历中,有使用到和网络连接相关的时候有三处:
一是电话本客服号码内置时,客服号码信息需要支持在线更新功能,当时有做应用与服务器连接取数据,然后判断是否要更新;
二是维护下载管理模块的时候,有分析过无法下载的问题时有了解过;
三是自己开发了一个自动下载谷歌play排名前1000应用的工具时,设计到下载功能;
想来这三处应该用到的都是Android里面自带的HttpUrlConnection工具类提供的功能,刚刚查了一下,这个还是java自带的。
https://docs.oracle.com/javase/8/docs/api/java/net/HttpURLConnection.html
从网上资料得知,在Android 2.3及以上版本,使用的是HttpURLConnection,而在Android 2.2及以下版本,使用的是HttpClient。这个是由于各个不同时期两者存在的bug和受重视程度不同有关,历史的车轮滚滚向前,版本迭代更新,目前肯定就是都乐于使用HttpUrlConnection 了。
HttpURLconnection是基于http协议的,支持get,post,put,delete等各种请求方式,最常用的就是get和post。但是我的代码中没有对此进行声明处理,例如电话本中下载客服号码信息文件的代码如下:
/**
* http connection
*
* return value: if failed :null
* succeed : inputstream
*/
public InputStream getInputStream(String urlStr) throws IOException {
InputStream is = null;
URL mUrl = null;
int mContentLength = 0;
try {
mUrl = new URL(urlStr);
Log.d(TAG,"[getInputStream]urlStr= "+urlStr+" ,url= "+mUrl.toString());
HttpURLConnection urlConn = (HttpURLConnection) mUrl.openConnection(); // 通过URL获取连接对象,此后没有设置请求方式是否为get还是post,默认就是get
Log.d(TAG,"[getInputStream] urlConn="+urlConn);
//set timeout time
urlConn.setConnectTimeout(10000); //设置连接超时时间
urlConn.setReadTimeout(10000);//设置读取超时时间
urlConn.setDoInput(true);// 允许写入,因为我这边是要从服务端获取,所以要输入,这个默认也是true. 而setDoOutput,设置是否要输出,默认false
is = urlConn.getInputStream(); //没有使用connect连接方法,直接获取数据流了,也没有出现问题,但是注意使用connect之后,就不要再设置参数了
Log.d(TAG,"[getInputStream] is="+is);
mContentLength = urlConn.getContentLength(); //如果使用了压缩Accept-Encoding: gzip需要注意这个长度是压缩长度。
Log.d(TAG,"mContentLength="+mContentLength);
if(mContentLength <= 0){
Log.w(TAG,"can not get file size");
return null;
}
} catch (MalformedURLException e) {
Log.e(TAG,"MalformedURLException");
e.printStackTrace();
}
catch(NetworkOnMainThreadException e){
Log.d(TAG,"NetworkOnMainThreadException ");
e.printStackTrace();
}
catch(UnknownHostException e){
Log.d(TAG,"UnknownHostException ");
e.printStackTrace();
}
catch(Exception e){
Log.d(TAG,"Exception ");
e.printStackTrace();
}
finally{
Log.d(TAG,"getInputStream over");
}
return is;
}
---------------在自动下载谷歌play应用的工具代码中,关于网络连接部分代码如下-----------------
/*
* url: download link
* name: the download apk name in the PC
* oldName: apk package name
*/
public static String download(String id ,String url, String name,String oldName){
URL e = null;
File file;
URLConnection uc;
int mFileSize = -1;
System.out.println("-----download id="+id+" url="+url+" name="+name+" oldName="+oldName);
try {
e = new URL(url);
uc = e.openConnection();
uc.addRequestProperty("User-Agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"); // 这里主要是设置UA信息,不然有可能是下载不了
uc.connect();
file = new File(downpath + name);
//avoid download the same file again
if(file.exists()){
return STATUS_SUCCEED;
}
//get the download file size by 'content-length' field
mFileSize = uc.getContentLength();
InputStream is = uc.getInputStream();
System.out.println("download begin to copy stream....");
long start = System.currentTimeMillis();
//copy the stream to local storage
FileUtils.copyInputStreamToFile(is,file);
long end = System.currentTimeMillis();
System.out.println("download copy stream over!! spent time: "+(end-start)/1000+" s");
//record the result
if(mFileSize != -1){
//succeed , do nothing
}else{
//delete it if failed
if(file.isFile() && file.exists()) {
file.delete();
}
return STATUS_FAIL;
}
System.out.println(name+" "+mFileSize);
} catch (Exception var) {
System.out.println(" download Exception");
var.printStackTrace();
file = new File(downpath +name);
if(file.isFile() && file.exists()) {
file.delete();
}
return STATUS_EXCEPTION;
}
return STATUS_SUCCEED;
}
----------------关于在维护下载管理模块是对于http网路连接的一点认识-----------------
Gamil 和 雅虎邮箱在数据流量的情况下不能下载附件问题,当时分析到的是雅虎服务器没有给出Content-length 域的值,导致代码无法判断文件大小而做的一个
禁止下载的处理;另外在android原生代码里面4.4的逻辑是通过判断Content-length 还有 编码类型来看是否继续下载,5.1版本之后又增加了判断是否为持久连接的逻辑,所以从这一系列问题中可以看出,网络连接里面有很多细节事项参数需要注意:
1、文件大小 content-length
2、编码类型 encodetype,分块传输编码(Chunked transfer encoding)可以用来传输大文件,不会告诉content-length大小
3、连接类型: 持久连接 和 非持久连接 ,HTTP/1.0使用非持久连接,HTTP/1.1默认使用持久连接,事物处理结束后,不关闭TCP连接。
1)HTTP/1.0 + keep-alive 连接, 即默认为非持久,如果要需要发送请求时增加 Connection:Keep-Alive
2) HTTP/1.1 + persistent 连接, 即默认为持久连接,如果需要关闭需要在最后一条请求中发送一个Connection:close请求首部
以上只是我在实际工作中碰到的一些场景知识的总结,实际HTTPUrlConnection的使用场景更多,除了我这边用到的下载文件,还有上传参数,上传文件等,具体可以参考: https://blog.csdn.net/fightingXia/article/details/71775516
-----------------关于socket tcp/ip http 的一点了解--------------------
socket套接字包含了五个信息:使用协议类型,源地址IP , 源端口, 目标地址IP, 目标地址端口, 是实现TCP/IP协议栈的一种工具,提供接口,方便调用;
TCP/IP 是传输层的协议,基于网络层IP协议,定义了数据如何传输,里面有三次握手规则来确保TCP连接的建立:
1、客户端发送SYNC同步状态给服务端, 进入同步发送状态;
2、服务端收到SYNC同步信号,进行ACK确认+1处理,然后发送SYNC+ACK给客户端,进入同步接受状态;
3、客服端接受到SYNC+ACK之后,进行确认ACK+1,发送给服务端;
然后连着进入连接建立状态, 之所以是三次握手是从稳定性和效率两方面来考虑的。
HTTP协议是应用层协议,即数据如何包装解析呈现给应用,每次请求都需要服务器响应,是一种短连接。