文章目录
- 一、网络基础知识
- 1、网络结构分层
- 1.1、IP(Internet Protocol)协议
- 1.2、TCP(Transmission Control Protocol)协议
- 1.3、分层结构对应的协议
- 1.应用层 - (HTTP、FTP、DNS、SMTP等协议)
- 2.传输层 - (TCP、UDP协议)
- 3.网络层 -(IP协议)
- 4. 数据链路层 (ARP协议)
- 5.物理层
- 2、IP地址和端口号
- 2.1、IP地址
- 2.2、端口号
- 3、HTTP
- 3.1 请求报文与响应报文
- 3.2 GET和POST请求
- 3.3 HTTP的缓存机制
- 1.cache-control 主要包括以下几个字段:
- 2.ETag
- 3.4 Cookie
- 4、Socket
- 二、Android中的HTTP请求
- 1. java.net包下的HttpURLConnection
- 1.1 GET方式请求
- 1.2 POST方式请求
- 2. org.apache.http 包下的HttpClient
- 2.1 GET方式(HttpGet)请求
- 2.2 POST方式(HttpPost)请求
一、网络基础知识
1、网络结构分层
国际标准化组织ISO于1978年提出“开发系统互连参考模型”,即注明的OSI(Open System Interconnection)。该模型力求简化,并以模块化的方式来设计网络,把计算机网络分成了七层:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。OSI模式已成为各种计算机网络结构的参考标准。
1.1、IP(Internet Protocol)协议
通信协议是网络通信的基础,IP协议则是一种非常重要的通信协议。IP协议又称互联网协议,是支持网络间互联的数据包协议。它提供网间连接的完善功能,包括IP数据报规定互联网络范围内的地址格式。
1.2、TCP(Transmission Control Protocol)协议
经常与IP协议放在一起的还有TCP协议,即传输控制协议,它规定一种可靠的数据信息传递服务。虽然IP和TCP这两个协议功能不尽相同,也可以分开单独使用,但是他们是在同一个时期作为一个协议来设计的,并且再功能上是互补的。因此实际使用中常常把这两个协议统称为TCP/IP协议,TCP/IP协议最早出现在UNIX操作系统中,现在几乎所有的操作系统都支持TCP/IP协议,因此TCP/IP协议也是Internet中最常用的基础协议。
按照TCP/IP协议模型,网络被分为了四层的模型,这个模型和上述的OSI七层模型有如下图所示的对应关系:
1.3、分层结构对应的协议
1.应用层 - (HTTP、FTP、DNS、SMTP等协议)
盖层定义了如何包装和解析数据,应用层如果是HTTP协议的话,则会按照该协议规定进行包装数据,如按照请求头、请求行、请求体包装,包装好数据后再将数据传至传输层。
2.传输层 - (TCP、UDP协议)
传输层有TCP和UDP两种协议,分别对应可靠的运输和不可靠的运输,如TCP因为要提供可靠的运输,如TCP因为要提供可靠的传输,所以内部要解决如何建立连接,如何保证传输是可靠的不丢数据,如何调节流量控制和拥塞控制。该层,我们平常一般是和socket打交道,Socket是一组封装的编程调用接口,通过它,我们能操作TCP、UDP进行连接的建立等。我们使用Socket进行连接建立的时候,一般都要指定端口号,所以这一层指定了把数据送到对应的端口号信息。
TCP是面向连接、数据可靠,有序的,但是以字节流的形式发送数据,所以速度慢。适用于需要安全稳定传输数据的场景。如HTTP、HTTPS网络协议,FTP文件传输协议以及POP、SMTP邮件传输协议;交易类、支付类软件都要基于TCP协议的Socket连接进行安全可靠的数据传输。
UDP不回去建立连接,它不管目的地是否存在,直接将数据发送给目的地,同时不会过问发送的数据是否丢失,到达的数据是否顺序错乱。因此UDP特点:不面向连接、数据不可靠、无序的、速度快,适用于需要实时性较高且不较为关注数据结果的场景,例如:音频通话、视频会议、广播电台等。
3.网络层 -(IP协议)
这一层是IP协议,以及一些路由选择协议等等,所以这一层指定了数据要传输到哪个IP地址。中间涉及到一些最优线路,路由选择算法等。
4. 数据链路层 (ARP协议)
ARP协议负责把IP地址解析为MAC地址,即硬件地址,这样就找到了唯一对应的机器。
5.物理层
该层是最底层,提供二进制流传输服务,也就是真正开始通过传输介质(有线、无线)开始进行数据的传输了。
2、IP地址和端口号
2.1、IP地址
IP地址用于唯一标识网络中的一个通信实体,这个通信实体既可以是一台主机,也可以是一台打印机或者是路由器的某一端口。而在IP协议网络中传输的数据包,都必须使用IP地址来进行标识。每一个数据包都要包括一个源IP地址和一个目的IP地址,当该数据包在网络中进行传输时,这两个地址要保持不变,以确保网络设备总能根据确定的IP地址,将数据包从源通信实体送往指定的通信实体。
IP地址是数字型的,它是一个32位整数,但通常为了便于记忆把它分成4个8位的二进制数,每8位之间用圆点分隔开,每个8位二进制可以转化成一个0~255的十进制整数,因此我们日常看到的都是这种形式:203.10.127.99。
NIC(Internet Network Information Center) 统一负责全球Internet IP地址的规划、管理,而Inter NIC、APNIC、RIPE三大网络信息中心具体负责美国及其他地区的IP地址分配。其中APNIC负责亚太地区的IP管理,我国申请IP地址也要通过APNIC,APNIC的总部设在日本东京大学。
2.2、端口号
IP地址用于唯一标识网络上的一个通信实体,但一个通信实体可以有多个通信程序同时提供网络服务,此时还需要使用端口。
端口是一个16位的整数,用于表示数据交给通信实体的哪个通信程序处理。因此,端口就是应用程序与外界交流的出入口,它是一种抽象的软件结构,包括一些数据结构和I/O缓冲区。同一台机器上不能有两个程序使用同一个端口,端口号可以从0~65535,通常将它们分为如下三级:
- 公认端口 :0~1023 ,他们紧密绑定一些特定的服务;
- 注册端口: 1024~49151,他们松散的绑定一些服务。应用程序通常应该使用这个范围内的端口;
- 动态和/或私有端口: 49152~65535 , 这些端口是应用程序使用的动态端口,应用程序一般不会主动使用这些端口。
举一个例子可以帮助理解:如果把IP地址比作是街道和门牌号的话,端口可以比作房间号。
3、HTTP
HTTP是无连接无状态的,HTTP协议只是一个应用层协议,最终还是要靠传输层的如TCP协议向上提供的服务进行连接。无连接的含义是HTTP约定了每次连接只处理一个请求,一次请求完成后就断开连接,这样主要是为了缓解服务器的压力,减少连接对服务器资源的占用。也可以理解为建立连接实际是传输层的事情,对于应用层的HTTP来说,它就是无连接的,因为上层对下层无感知。无状态是指每个请求之间都是独立的,对于之前的请求事务没有记忆的能力。所以就出现了像Cookie这种用来保存一些状态的东西。
3.1 请求报文与响应报文
请求报文:
- 请求行: 由请求方法post/get、请求路径URL、协议版本等组成;
- 请求头:即header,包含了很多字段;
- 请求体:请求发送的数据内容
响应报文:
- 状态行: 由状态码如:200、404等、协议版本等组成;
- 响应头:即返回的header;
- 响应体:响应正文数据,即返回的数据内容信息
3.2 GET和POST请求
GET: 一般用于数据的获取操作,且GET参数的大小有限制,超出一定长度后会请求失败;
POST: 一般用户数据新增、更新或者删除操作,POST的数据大小没有做限制。
3.3 HTTP的缓存机制
HTTP的缓存主要是利用header里的两个字段来控制的:
1.cache-control 主要包括以下几个字段:
* 1)private:只有客户端可以缓存;
* 2)public:客户端和代理服务器都可以缓存;
* 3)max-age:缓存的过期时间;
* 4)no-cache:需要使用对比缓存来验证缓存数据,如果该字段打开,即便max-age没有失效也会发起一次请求确认资源是否有更新;
* 5)no-store:所有内存都不会进行缓存
实际上就是在这里设置了一个缓存策略,由服务器端第一次通过header下发给客户端,
Okhttp中对于网络请求缓存这一块就是利用了HTTP的缓存机制。
2.ETag
该字段用于上述no-cache进行对比缓存,ETag是服务端资源的一个标识码。当客户端发送第一次请求时,服务端会下发当前请求资源的标识码ETag,下次再请求时,客户端则会通过header里的If-None-Match将这个标识码ETag带上,服务端将客户端传来的ETag与最新的ETag做对比,如果一样,则表示没有更新,返回304,去本地缓存即可;如果有更新,则返回最新的资源。
3.4 Cookie
因为HTTP协议是无状态的,因此cookie的作用就是用来在本地缓存记住一些状态的,一个cookie一般都包含domin(所属域)、path、expires(过期时间)等属性,服务端可以通过在响应头里的set-cookies将状态写入客户端的cookie。客户发起请求时将cookie带上
4、Socket
socket是一组操作TCP/UDP的API,像HttpURLConnection和okhttp这种涉及到比较底层的网络请求发送的,最终当然也都是通过socket来进行网络请求连接发送,而Volley、Retrofit则是更上层的封装,最后是依靠HttpURLConnection或者Okhttp来进行最终的连接建立和请求发送。
二、Android中的HTTP请求
1. java.net包下的HttpURLConnection
1.1 GET方式请求
// Get方式请求
public static void requestByGet() throws Exception {
String path = "请求地址加参数";
// 新建一个URL对象
URL url = new URL(path);
// 打开一个HttpURLConnection连接,建立TCP连接
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
// 设置连接超时时间 单位是毫秒
urlConn.setConnectTimeout(5 * 1000);
// 发起请求
urlConn.connect();
// 判断请求是否成功
if (urlConn.getResponseCode() == HTTP_200) {
// 获取返回的数据,获取到的是字节流
byte[] data = readStream(urlConn.getInputStream());
Log.i(TAG_GET, "请求成功,返回数据如下:");
Log.i(TAG_GET, new String(data, "UTF-8"));
} else {
Log.i(TAG_GET, "请求失败");
}
// 关闭连接
urlConn.disconnect();
}
1.2 POST方式请求
// Post方式请求
public static void requestByPost() throws Throwable {
String path = "请求地址";
// 将请求的参数转换为byte数组
String params = "id=" + URLEncoder.encode("10212", "UTF-8")
+ "&pwd=" + URLEncoder.encode("23513w", "UTF-8");
byte[] postData = params.getBytes();
// 新建一个URL对象
URL url = new URL(path);
// 创建请求连接,TCP连接
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
// 设置连接超时时间
urlConn.setConnectTimeout(5 * 1000);
// Post方式请求必须设置允许输出
urlConn.setDoOutput(true);
// Post方式请求不能使用缓存
urlConn.setUseCaches(false);
// 设置请求方式为Post请求
urlConn.setRequestMethod("POST");
urlConn.setInstanceFollowRedirects(true);
// 配置请求Content-Type
urlConn.setRequestProperty("Content-Type",
"application/x-www-form-urlencode");
// 发起请求
urlConn.connect();
// 发送请求参数
DataOutputStream dos = new DataOutputStream(urlConn.getOutputStream());
dos.write(postData);
dos.flush();
dos.close();
// 判断请求是否成功
if (urlConn.getResponseCode() == HTTP_200) {
// 获取返回的数据
byte[] data = readStream(urlConn.getInputStream());
Log.i(TAG_POST, "请求成功,返回数据如下:");
Log.i(TAG_POST, new String(data, "UTF-8"));
} else {
Log.i(TAG_POST, "请求失败");
}
}
2. org.apache.http 包下的HttpClient
2.1 GET方式(HttpGet)请求
public static void requestByHttpGet() throws Exception {
String path = "请求地址和参数";
// 创建HttpGet对象
HttpGet httpGet = new HttpGet(path);
// 创建HttpClient对象
HttpClient httpClient = new DefaultHttpClient();
// HttpResponse实例
HttpResponse httpResp = httpClient.execute(httpGet);
// 判断是否请求成功
if (httpResp.getStatusLine().getStatusCode() == HTTP_200) {
// 获取返回的数据
String result = EntityUtils.toString(httpResp.getEntity(), "UTF-8");
Log.i(TAG_HTTPGET, "请求成功,返回数据如下:");
Log.i(TAG_HTTPGET, result);
} else {
Log.i(TAG_HTTPGET, "请求失败");
}
}
2.2 POST方式(HttpPost)请求
// HttpPost方式请求
public static void requestByHttpPost() throws Exception {
String path = "请求地址";
// 新建HttpPost对象
HttpPost httpPost = new HttpPost(path);
// Post参数
List<PostData> params = new ArrayList<PostData>();
params.add(new PostData("id", "12012"));
params.add(new PostData("pwd", "12345w"));
// 设置字符集
HttpEntity entity = new UrlEncodedFormEntity(params, HTTP.UTF_8);
// 设置参数实体
httpPost.setEntity(entity);
// 获取HttpClient对象
HttpClient httpClient = new DefaultHttpClient();
// 获取HttpResponse实例
HttpResponse httpResp = httpClient.execute(httpPost);
// 判断是否请求成功
if (httpResp.getStatusLine().getStatusCode() == HTTP_200) {
// 获取返回的数据
String result = EntityUtils.toString(httpResp.getEntity(), "UTF-8");
Log.i(TAG_HTTPGET, "请求成功,返回数据如下:");
Log.i(TAG_HTTPGET, result);
} else {
Log.i(TAG_HTTPGET, "请求失败");
}
}
基于HttpURLConnection的三方网络框架有:xUtils3
基于HttpClient的三方网络框架:Volley、afinal、xUtils(基于afinal重写的) 、AsyncHttpClient
由于在Android5.0的时候Google就不推荐使用HttpClient了,到了Android6.0(API 23)SDK,不再提供org.apache.http.*(只保留了几个类),因此编译版本为23及以上时,使用了HttpClient相关类的库或项目:如android-async-http等会出现类找不到的报错。