Android中的网络基础知识

一、网络基础知识

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等会出现类找不到的报错。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值