计算机网络及其协议
概述
OSI/RM
在1978年国际标准化组织(ISO)提出了“开放系统互连参考模型”,即著名的OSI/RM 模型(Open System Interconnection/Reference Model)。此后,不同厂家生产的计算机便能相互通信,建立起了计算机网络。OSI/RM将计算机网络体系结构的通信协议划分为七层,自下而上依次为:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。
IP、TCP 和UDP 协议
由于OSI/RM 模型过于复杂也难以实现,现实中广泛应用的是TCP/IP 模型。它是由ARPA 于1977 年到1979 年推出的一种网络体系结构和协议规范。TCP/IP 是一个协议集,而非指TCP 和 IP 两种协议。在很多情况下,它是利用IP 进行通信时所必须用到的协议群的统称。具体来说,IP 或 ICMP、TCP 或 UDP、TELNET 或 FTP、以及 HTTP 等都属于 TCP/IP 协议。他们与 TCP 或 IP 的关系紧密,是互联网必不可少的组成部分。TCP/IP 一词泛指这些协议,因此,有时也称 TCP/IP 为网际协议群。互联网进行通信时,需要相应的网络协议,TCP/IP 原本就是为使用互联网而开发制定的协议族。因此,互联网的协议就是 TCP/IP,TCP/IP 就是互联网的协议。
TCP/IP 模型也是分层模型,分为4 层。OSI/RM 模型与TCP/IP 模型的参考层次如图所示:
应用层:是大多数普通与网络相关的程序为了通过网络与其他程序通信所使用的层。在应用层中,数据以应用内部使用的格式进行传送,然后被编码成标准协议的格式。如HTTP 协议、FTP 协议、接收电子邮件的POP3 和IMAP 协议、发送邮件的SMTP 协议,以及远程登录使用的SSH 和Telnet 等。所以用户通常是与应用层进行交互。
传输层:提供两台主机之间透明的数据传输,通常用于端到端连接、流量控制或错误恢复。这一层的两个最重要的协议是TCP(Transmission Control Protocol,传输控制协议)和UDP(User Datagram Protocol,用户数据报协议)。
网络层:提供端到端的数据包交付,它负责数据包从源发送到目的地,任务包括网络路由、差错控制和IP 编址等。这一层包括的重要协议有IP(版本4 和版本6)、ICMP(Internet Control Message Protocol,Internet 控制报文协议)和IPSec(Internet Protocol Security,Internet 协议安全)。
网络接口层:负责通过网络发送和接收IP 数据报;允许主机连入网络时使用多种现成的与流行的技术,如以太网、令牌网、帧中继、ATM、X.25、DDN、SDH、WDM 等。
一个应用层应用一般都会使用到两个传输层协议之一:面向连接的TCP 传输控制协议 和 面向无连接的UDP 用户数据报协议。下面分析TCP/IP 协议栈中常用的IP、TCP 和UDP 协议。
IP 协议
互联网协议(Internet Protocol,IP)是用于报文交换网络的一种面向数据的协议。IP是在TCP/IP 协议中网络层的主要协议,任务是根据源主机和目的主机的地址传送数据。为达到此目的,IP 定义了寻址方法和数据报的封装结构。第一个架构的主要版本,现在称为IPv4,仍然是最主要的互联网协议。当前世界各地正在积极部署IPv6。
TCP 协议
传输控制协议(Transmission Control Protocol,TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议。流就是指不间断的数据结构,当应用程序采用 TCP 发送消息时,虽然可以保证发送的顺序,但还是犹如没有任何间隔的数据流发送给接收端。TCP 为提供可靠性传输,可以进行丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制的机制。此外,因为TCP 作为一种面向有连接的协议,只有在确认通信对端存在时才会发送数据,从而还具备“流量控制”、“拥塞控制”、提高网络利用率等众多功能。著名的三次握手就是指建立一个 TCP 连接时需要客户端和服务器端总共发送三个包以确认连接的建立,而终止TCP连接就是四次挥手,需要客户端和服务端总共发送4个包以确认连接的断开。
UDP 协议
用户数据报协议(User Datagram Protocol ,UDP)是TCP/IP 模型中一种面向无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。UDP 协议基本上是IP 协议与上层协议的接口。UDP 协议适用于端口分别运行在同一台设备上的多个应用程序中。与TCP 不同,UDP 并不提供对IP 协议的可靠机制、流控制以及错误恢复功能等,在数据传输之前不需要建立连接。由于UDP 比较简单,UDP 头包含很少的字节,所以比TCP负载消耗少。UDP 适用于不需要TCP 可靠机制的情形,比如,当高层协议或应用程序提供错误和流控制功能的时候。UDP 服务于很多知名应用层协议,包括网络文件系统(Network File System,NFS)、简单网络管理协议(Simple Network Management Protocol,SNMP)、域名系统(DomainName System,DNS)以及简单文件传输系统(Trivial File Transfer Protocol,TFTP)。
在Android 中使用TCP、UDP 协议
Socket字面翻译是“插座”,通常也称作“套接字”,是对TCP/IP的封装的编程接口。Socket把复杂的TCP/IP 协议族隐藏在Socket 接口后面。Socket 用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过Socket向网络发出请求或者应答网络请求。就像一台服务器可能会提供很多服务,每种服务对应一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务,或者比喻成每个服务就是一个Socket插座,客户端若是需要哪种服务,就将它的Socket插头插到相应的插座上面。有一个比喻:HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。
Socket 的基本操作包括:
连接远程机器
发送数据
接收数据
关闭连接
绑定端口
监听到达数据
在绑定的端口上接受来自远程机器的连接
服务器要和客户端通信,两者都要实例化一个Socket:
客户端(java.net. Socket)可以实现连接远程机器、发送数据、接收数据、关闭连接等
服务器(java.net. ServerSocket)还需要实现绑定端口,监听到达的数据,接受来自远程机器的连接。
Socket 一般有两种类型:TCP 套接字和UDP 套接字。两者都接收传输协议数据包并将其内容向前传送到应用层。
TCP 把消息分解成数据包(数据报,datagrams)并在接收端以正确的顺序把它们重新装配起来,TCP 还处理对遗失数据包的重传请求,位于上层的应用层要处理的事情就少多了。
UDP 不提供装配和重传请求这些功能,它只是向前传送信息包。位于上层的应用层必须确保消息是完整的,并且是以正确的顺序装配的。
使用TCP 通信
TCP 建立连接之后,通信双方都同时可以进行数据的传输;在保证可靠性上,采用超时重传和捎带确认机制;在流量控制上,采用滑动窗口协议,协议中规定,对于窗口内未经确认的分组需要重传;在拥塞控制上,采用慢启动算法
TCP 服务器端工作的主要步骤如下:
步骤1 调用ServerSocket(int port)创建一个ServerSocket,并绑定到指定端口上。
步骤2 调用accept(),监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字。
步骤3 调用Socket 类的getOutputStream() 和getInputStream() 获取输出和输入流,开始网络数据的发送和接收。
步骤4 关闭通信套接字。
示例代码如下所示:
private int TCP_SERVER_PORT = 8080;
private void serverTCPFunction() {
ServerSocket serverSocket = null;
try {
// TCP_SERVER_PORT 为指定的绑定端口,为int 类型
serverSocket = new ServerSocket(TCP_SERVER_PORT);
// 监听连接请求
Socket socket = serverSocket.accept();
// 获取输入流 并 写入读Buffer 中
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 获取输出流 并 放到写Buffer 中
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
// 读取接收信息,转换为字符串
String incomingMsg = in.readLine() + System.getProperty("line.separator");
// 生成发送字符串
String outgoingMsg = "goodbye from port " + TCP_SERVER_PORT + System.getProperty("line.separator");
// 将发送字符串写入上面定义的BufferedWriter 中
out.write(outgoingMsg);
// 刷新,发送
out.flush();
// 关闭
socket.close();
} catch (InterruptedIOException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 判定是否初始化ServerSocket 对象,如果初始化则关闭serverSocket
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
TCP 客户端工作的主要步骤如下:
步骤1 调用Socket() 创建一个流套接字,并连接到服务器端。
步骤2 调用Socket 类的getOutputStream() 和getInputStream() 方法获取输出和输入流,开始网络数据的发送和接收。
步骤3 关闭通信套接字。
编写TCP 客户端代码如下所示:
private void clientTCPFunction() {
try {
// 初始化Socket,TCP_SERVER_PORT 为指定的端口,int 类型
Socket socket = new Socket("localhost", TCP_SERVER_PORT);
// 获取输入流
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 生成输出流
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
// 生成输出内容
String outMsg = "TCP connecting to " + TCP_SERVER_PORT + System.getProperty("line.separator");
// 写入
out.write(outMsg);
// 刷新,发送
out.flush();
// 获取输入流
String inMsg = in.readLine() + System.getProperty("line.separator");
// 关闭连接
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
使用UDP 通信
UDP 有不提供数据报分组、组装和不能对数据包排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。UDP 用来支持那些需要在计算机之间传输数据的网络应用,包括网络视频会议系统在内的众多的客户端/ 服务器模式的网络应用都需要使用UDP 协议。UDP 协议的主要作用是将网络数据流量压缩成数据报的形式。一个典型的数据报就是一个二进制数据的传输单位。
UDP 服务器端工作的主要步骤如下:
步骤1 调用DatagramSocket(int port) 创建一个数据报套接字,并绑定到指定端口上。
步骤2 调用DatagramPacket(byte[]buf,int length),建立一个字节数组以接收UDP 包。
步骤3 调用DatagramSocket 类的receive(),接受UDP 包。
步骤4 关闭数据报套接字。
示例代码如下所示:
private int UDP_SERVER_PORT = 9090;
private int MAX_UDP_DATAGRAM_LEN = 1024;
private void serverDUPFunction() {
// 接收的字节大小,客户端发送的数据不能超过MAX_UDP_DATAGRAM_LEN
byte[] lMsg = new byte[MAX_UDP_DATAGRAM_LEN];
// 新建一个DatagramSocket 类
DatagramSocket ds = null;
try {
// UDP 服务器监听的端口
ds = new DatagramSocket(UDP_SERVER_PORT);
// 实例化一个DatagramPacket 类
DatagramPacket dp = new DatagramPacket(lMsg, lMsg.length);
// 准备接收数据
ds.receive(dp);
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ds != null) {
ds.close();
}
}
}
UDP 客户端工作的主要步骤如下:
步骤1 调用DatagramSocket() 创建一个数据包套接字。
步骤2 调用DatagramPacket(byte[]buf,int offset,int length,InetAddress address,int port),建立要发送的UDP 包。
步骤3 调用DatagramSocket 类的send() 发送UDP 包。
步骤4 关闭数据报套接字。
示例代码如下所示:
private void clientDUPFunction() {
// 定义需要发送的信息
String udpMsg = "hello world from UDP client " + UDP_SERVER_PORT;
// 新建一个DatagramSocket 对象
DatagramSocket ds = null;
try {
// 初始化DatagramSocket 对象
ds = new DatagramSocket();
// 初始化InetAddress 对象
InetAddress serverAddr = InetAddress.getByName("127.0.0.1");
// 初始化DatagramPacket 对象
DatagramPacket dp = new DatagramPacket(udpMsg.getBytes(), udpMsg.length(), serverAddr, UDP_SERVER_PORT);
// 发送
ds.send(dp);
}
catch (SocketException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (ds != null) {
ds.close();
}
}
}
经典的Socket 聊天室示例
服务端TCPServerService.java代码:
public class TCPServerService extends Service {
public final static int SERVER_PORT = 1234;
private boolean mIsDestoryed = false;
private ServerSocket mServerSocket;
@Override
public void onCreate() {
super.onCreate();
new Thread() {
@Override
public void run() {
initTcpServer();
}
}.start();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
mIsDestoryed = true;
if (mServerSocket != null) {
try {
mServerSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void initTcpServer() {
// 初始化ServerSocket
try {
mServerSocket = new ServerSocket(SERVER_PORT);
} catch (IOException e) {
e.printStackTrace();
return;
}
// 一直处于检测客户端连接,可连接多个客户端
while (!mIsDestoryed) {
try {
// 接受客户端请求,若无客户端请求则堵塞
final Socket client = mServerSocket.accept();
new Thread() {
@Override
public void run() {
try {
responseClient(client);
} catch (IOException e) {
e.printStackTrace();
}
}
;
}.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void responseClient(Socket socket) throws IOException {
// 用于接收客户端消息
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 用于向客户端发送消息
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
out.println("已经跟客户端连接上了");
while (!mIsDestoryed) {
// 读取客户端消息,若无消息,则阻塞住
String str = in.readLine();
if (str == null) {
break;
}
String msg = "我收到你消息了";
out.println(msg);
// out.write(msg);
// out.flush();
}
// 关闭流
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
if (socket != null) {
socket.close();
}
}
}
客户端MainActivity.java代码:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private Button mSendButton;
private PrintWriter mPrintWriter;
private Socket mClientSocket;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSendButton = findViewById(R.id.send);
mSendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mPrintWriter == null) {
return;
}
String msg = "发送消息";
mPrintWriter.println(msg);
Log.d(TAG, "Client :" + msg);
}
});
startService();
connectTCPServer();
}
private void startService() {
Intent service = new Intent(this, TCPServerService.class);
startService(service);
}
private void connectTCPServer() {
new Thread() {
@Override
public void run() {
onConnectTCPServer();
}
}.start();
}
private void onConnectTCPServer() {
while (mClientSocket == null) {
try {
mClientSocket = new Socket("localhost", TCPServerService.SERVER_PORT);
mPrintWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(mClientSocket.getOutputStream())), true);
} catch (IOException e) {
// 若连接失败,则每2秒后重试
SystemClock.sleep(2000);
}
}
try {
// 接收服务器端的消息
BufferedReader br = new BufferedReader(new InputStreamReader(mClientSocket.getInputStream()));
while (!MainActivity.this.isFinishing()) {
// 读取服务端消息,若无消息,则阻塞住
String msg = br.readLine();
Log.d(TAG, "Server :" + msg);
}
if (br != null) {
br.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (mClientSocket != null) {
try {
mClientSocket.shutdownInput();
mClientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
if (mPrintWriter != null) {
mPrintWriter.close();
}
}
}
}
}
程序运行后,便会在onCreate中连接服务,日志:
MainActivity: Server :已经跟客户端连接上了
当按下按钮后,便会向服务端发送一条信息,此时服务端收到信息也回复了一条信息,日志:
MainActivity: Client :发送消息
MainActivity: Server :我收到你消息了
Android 中的HTTP 编程
我们曾经有过文章《Android Volley的使用(一)基本网络请求》介绍过在Android程序开发中使用网络请求的情况,使用Volley框架固然是一个很不错的选择。但是如果你的程序正在面临着size变大的问题,刚好就只需要一个简单的这方面功能时,你就不得不要放弃使用第三方框架,改为SDK自带的来自己编写。Android本身提供了httpClient和HttpURLConnection来进行网络请求通信。
HttpClient
的优势在于处理一些可能需要用户登录而且具有相应的权限才可访问该页面。例如需要涉及Session、Cookie的处理时,就要使用HttpClient。但是,在Android 6.0 SDK版本已经将HttpClient类库移除了,如果想继续使用它,可以在相应的module下的build.gradle中加入:
android {
useLibrary 'org.apache.http.legacy'
}
使用示例
/**
* HttpClient的Get请求
* @param url 请求的URL
* @return
*/
public static String httpClientGet(String url) {
InputStream inStream = null;
HttpClient httpclient = null;
try {
httpclient = new DefaultHttpClient();
HttpResponse response = httpclient.execute(new HttpGet(url));
inStream = response.getEntity().getContent();
String result = inputStreamToString(inStream);
return result;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (inStream != null) {
inStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
httpclient.getConnectionManager().shutdown();
}
return null;
}
/**
* HttpClient的Post请求
* @param url 请求的URL
* @param nameValuePairs 请求参数,值的添加如:nameValuePairs.add(new BasicNameValuePair("id", "12345"));
* @return
*/
public static String httpClientPost(String url, List<NameValuePair> nameValuePairs) {
InputStream inStream = null;
HttpClient httpclient = null;
try {
httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs ,"UTF-8"));
HttpResponse response = httpclient.execute(httppost);
inStream = response.getEntity().getContent();
String result = inputStreamToString(inStream);
return result;
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (inStream != null) {
inStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
httpclient.getConnectionManager().shutdown();
}
return null;
}
/**
* 将InputStream 格式转化为StringBuilder 格式
* @param is
* @return
*/
private static String inputStreamToString(InputStream is) {
String line = "";
StringBuilder sb = new StringBuilder();
try {
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
while ((line = rd.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
// 或
// Scanner scanner = new Scanner(is).useDelimiter("\\A");
// return scanner.hasNext() ? scanner.next() : "";
}
HttpURLConnection
如果在一般的网络请求情况下,只是需要简单的网络请求或表单提交请求,HttpURLConnection则是最佳的选择。它的API简单,体积较小。压缩和缓存机制可以有效地减少网络访问的流量,在提升速度和省电方面也起到了较大的作用。正如在Android 6.0版本后官方将HttpClient移除也是建议我们在开中发使用HttpURLConnection。
使用示例
/**
* HttpURLConnection的Get请求
* @param urlStr
* @return
*/
public static String httpURLConnectionGet(String urlStr) {
InputStream inStream = null;
HttpURLConnection conn = null;
try {
URL url = new URL(urlStr);
conn = (HttpURLConnection)url.openConnection();
// conn.setConnectTimeout(timeOut);
// conn.setReadTimeout(readTimeout);
conn.setRequestMethod("GET");
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
return null;
}
inStream = conn.getInputStream();
String result = inputStreamToString(inStream);
return result;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (inStream != null) {
inStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if (conn != null) {
conn.disconnect();
}
}
return null;
}
public static String HttpURLConnectionPost(String urlStr, String params) {
HttpURLConnection conn = null;
InputStream inStream = null;
PrintWriter printWriter = null;
try {
URL url = new URL(urlStr);
conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true); // 是否输入参数
//conn.setConnectTimeout(timeOut); // 连接超时 单位毫秒
//conn.setReadTimeout(readTimeout); // 读取超时 单位毫秒
conn.setUseCaches(false); // Post 请求不能使用缓存
// 第1种方式:使用直接输出流的方式(已知输出流的长度):
// conn.setFixedLengthStreamingMode(输出流的固定长度);
// 第2种方式:使用直接输出流的方式(未知输出流的长度):
conn.setChunkedStreamingMode(5); // 5 为块的大小
// 第3种方式:本地缓存后一次性输出:
// 两个函数都不指定
conn.setRequestMethod("POST");
// application/x-javascript text/xml ->xml数据
// application/x-javascript ->json对象
// application/x-www-form-urlencoded ->表单数据
// 在给HttpURLConnection 设置request属性的时候,Android4.0+自动对属性的内容中的空格进行了转义替换‘\s’。
// 但是,Android2.0+ 没有做这个处理,所以有些网络访问一直Bad!
conn.setRequestProperty("Content-Type", ("application/x-www-form-urlencoded; charset=utf-8").replaceAll("\\s", ""));
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("Content-Length", String.valueOf(params.length()));
//PrintWriter 是文本。也就是unicode编码格式的,当然也包括汉字。
printWriter = new PrintWriter(conn.getOutputStream());
printWriter.write(params);
printWriter.flush();
// OutputStream 接受的是bytes
// byte[] data = params.getBytes("UTF-8");
// OutputStream outputStream = conn.getOutputStream();
// outputStream.write(data);
// outputStream.flush();
//DataOutputStream 是OutputStream的一个实用类,写byte,写String都可以
// DataOutputStream dataOutputStream = new DataOutputStream(conn.getOutputStream());
// dataOutputStream.writeBytes(params);
// dataOutputStream.flush();
if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){
inStream = new BufferedInputStream(conn.getInputStream());
} else {
inStream = new BufferedInputStream(conn.getErrorStream());
}
String result = inputStreamToString(inStream);
return result;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (conn != null) {
conn.disconnect();
}
if (printWriter != null) {
printWriter.close();
}
try {
if (inStream != null) {
inStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
下载文件的示例:
public static boolean downloadZip(Context ctx, String urlStr) {
InputStream is = null;
FileOutputStream fos = null;
boolean bRet = false;
HttpURLConnection conn = null;
try {
File zipFile = getDownloadFile(ctx); // 例如:/data/data/com.zyx.demo/mydownload/xx.zip
URL url = new URL(urlStr);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(5000);
conn.setConnectTimeout(5000);
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
return false;
}
is = conn.getInputStream();
fos = new FileOutputStream(zipFile);
byte[] buffer = new byte[1024];
int len = 0;
while ((len = is.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
bRet = true;
} catch (Exception e) {
} finally {
try {
if (is != null) {
is.close();
}
if (fos != null) {
fos.close();
}
if (conn != null) {
conn.disconnect();
}
} catch (Exception e) {
}
}
return bRet;
}
public static File getDownloadFile(Context ctx) {
try {
String dexDir = ctx.getDir("mydownload", Context.MODE_PRIVATE).getAbsolutePath();
String path = dexDir + File.separator + "xx.zip";
return new File(path);
} catch (Exception e) {
}
return null;
}