每日一题:网络编程概述
面试率: ★★★★★
面试提醒
网络编程是个十分重要知识点,在移动端和服务端,前端都扮演着十分重要的位置,Android中几乎只要是上线的项目基本都会涉及到网络,应聘者们应该熟悉掌握该技术.
面试技巧
网络编程概念会比较多,你可能要掌握Android平台下的常见网络API接口;一些相关网络协议;网络架构和数据传输;网络安全.
从上面看来我们要掌握的内容实在太多了,为了简化我们的准备工作,提供以下几个技巧:
网络库掌握技巧
面试中经常会被问到一些比较流行的网络框架,如okHttp,而okHttp源码中包含了协议,缓存,架构,加密,压缩,异步,并发等技术,没错你要掌握的就是把okHttp的源码熟悉掌握下来,而外面目前有很多这相关的资料博文.
这种掌握技巧可以比较有条理的全局去掌握网络编程,并从中学习到一些大神代码书写规范.分类掌握技巧
- 智能硬件
如面试智能硬件的公司你主要要掌握的是相关的WIFI,蓝牙,Socket. - 视频直播
Android这边要了解jni,ndk,媒体协议(hls、rtsp、rtmp等),另外还有流服务器. - 新闻电商
服务端分页加载大数据,网络框架封装,js与java交互等
面试题
下面通过一些比较常见的面试题来,提高我们对Android网络编程的了解.
Android中常见的网络API接口了解多少?
首先,你应该先了解的下面几个概念:
- Android平台网络相关API接口
- Java.NET.* (标准Java接口)
java.Net.* 提供与联网有关的类,包括流、数据包套接字(socket) 、Internet 协议、常见Http处理等。比如:创建URL,以及URLConnection /HttpURLConnection 对象、设置链接参数、链接到服务器、向服务器写数据、从服务器读取数据等通信。这些在Java网络编程中均有涉及。 - Org.apache 接口
对于大部分应用程序而言JDK本身提供的网络功能已远远不够,这时就需要Android提供的Apache HttpClient 了。它是一个开源项目,功能更加完善,为客户端的Http编程提供高效、最新、功能丰富的工具包支持。 - Android.net.* (Android网络接口)
常常使用此包下的类进行Android特有的网络编程,如:访问WiFi,访问Android联网信息,邮件等功能。
常见的网络架构有几种?
网络架构主要有两种模式B/S,C/S
- B/S----> 就是浏览器/服务器端模式了,通过应用层的HTTP协议通信,不需要特定客户端软件,而是需要统一规范的客户端,简而言之就是Android网络浏览器(如chrome,UcWeb,QQ浏览器等等)访问web服务器端的方式了。
- C/S----> 就客户端/服务器端模式,通过任意的网络协议通信,需要特定的客户端软件。
服务器一般会返回什么类型数据给客户端?
服务器端返回客户端的内容有三种方式:
- 以HTML代码的形式返回。
- 以XML字符串的形式返回,做Android开发时这种方式比较多。返回的数据需要通过XML解析(SAX、DOM,Pull,等)器进行解析(必备知识)。
- 以json对象的方式返回(开发常用)。
从长连接和短连接的角度分析Android的网络编程分为2种:基于socket的 和 基于http协议的
说说你对socket的了解
socket基本概念
- 三元组(ip地址,协议,端口)
Socket 是对 TCP/IP 协议族的一种封装,是应用层与TCP/IP协议族通信的中间软件抽象层。从设计模式的角度看来,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
Socket 还可以认为是一种网络间不同计算机上的进程通信的一种方法,利用三元组(ip地址,协议,端口)就可以唯一标识网络中的进程,网络中的进程通信可以利用这个标志与其它进程进行交互。
socket下的外观模式
外观模式(face pattern)
外观模式也叫门面模式
,虽然平时我们可能没什么听过这个模式,但是外面实际开发中很多时候也会使用到他,因为它完美地体现了依赖倒转原则
和迪米特法则
的思想,所以是非常常用的模式之一.
外观设计模式在什么时候用好?
这个要分三个阶段:
-
在设计初期阶段,应该要有意思的讲不通的两个层分离
,如经典的三层架构(mv*),就需要考虑数据层访问业务层,业务层和展示层的层与层之间建立外观Facade ,
这样可以为负责的子系统提供一个简单的接口,使得耦合大大降低. -
在开发阶段,子系统往往因为不断的重构演化而变得越来越复杂,
大多数的模式使用时也都会产生很多小的类,这本来是好事,但是也给外部调用它们的用户程序带来了使用上的困难,给这些小类添加外观Facade 可以提供一个简单的接口,减少它们之间的依赖.
-
在维护一个遗留的大型系统时,可能这个系统以及非常难以维护和拓展了,
但因为它包含非常重要的功能,新的需求必须要依赖于他.此时用外观模式Facade也是非常适合的.你可以为新的系统开发一个外观Facade 类,来提供设计粗糙或高度复杂的遗留代码的比较清晰的简单接口,让新的系统与Facade 对象交互, Facade与遗留代码交互所有复杂的工作.
实例:
农夫有很多家禽,如鸭,鸡,鹅,他们都需要喂养和照顾.
因为鸡鸭鹅吃的饲料都是一样的,所以如果农夫每种家禽都单独去做,这样的效率就会很低,而且整个过程也相当复杂,因此我们通过门面模式把要对鸡鸭鹅做的事情封装在 Poultry 家禽类中,里面过程不用理,只要提供 feed 和 care 的公共方法即可.
//class: Duck,Duck,Goose
//method: feed,care
class Poultry{
pig = new Pig();
duck = new Duck();
goose = new Goose();
void feedMethod(){
pig.feed();
duck.feed();
goose.feed();
}
void careMethod(){
pig.care();
duck.care();
goose.care();
}
}
基于TCP/IP协议之上的协议
使用HttpURLConnection连接URL
- GET请求
URL url = new URL(
"http://baidu.com");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(TIME);
conn.setReadTimeout(TIME);
int responseCode = conn.getResponseCode();
if (responseCode == 200) {
input = conn.getInputStream();
if (input != null) {
//TODO 把流转成String
}
}
- 记得设置连接超时,如果网络不好,Android系统在超过默认时间会收回资源中断操作.
- 返回的响应码200,是成功.
- 在Android中对文件流的操作和Java SE上面是一样的.
- 在对大文件的操作时,要将文件写到SDCard上面,不要直接写到手机内存上.
- 操作大文件是,要一遍从网络上读,一遍要往SDCard上面写,减少手机内存的使用.这点很重要,面试经常会被问到.
- 对文件流操作完,要记得及时关闭.
- POST请求
向服务器端发送请求参数,步骤:
String data = "username=justice&password=infiniteJustice";
URL url = new URL(
"http://192.168.31.144:10010/MINATest/servlet/DataTestServlet");
conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(TIME);
conn.setReadTimeout(TIME);
conn.setDoInput(true);// 允许输入
conn.setDoOutput(true);// 允许输出
conn.setUseCaches(false);// 不使用Cache
conn.setRequestProperty("Charset", ENCODING);
conn.setRequestProperty("Content-Length",
String.valueOf(data.length()));
conn.setRequestProperty("Content-Type", "text");//设置文件类型
conn.setRequestProperty("Charset", "UTF-8");//设置字符集
conn.setRequestProperty("Connection", "Keep-Alive");//设置长连接 conn.setRequestProperty("Content-Length", String.valueOf(data.length));//设置文件长度
conn.setRequestProperty("Accept“,” image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword");//设置HTTP请求头
conn.setRequestProperty("Accept-Language“,"zh-CN");//设置语言
conn.setRequestMethod("POST");
DataOutputStream outStream = new DataOutputStream(
conn.getOutputStream());
outStream.write(data.getBytes());
outStream.flush();
outStream.close();
if (conn == null) {
return;
}
int responseCode = conn.getResponseCode();
if (responseCode == 200) {
input = conn.getInputStream();
if (input != null) {
}
}
- 发送POST请求必须设置允许输出.
- 不要使用缓存,容易出现问题.
- 在开始用HttpURLConnection对象的setRequestProperty()设置,就是生成HTML文件头.
- 向服务器端发送xml数据(也称为实体Entity)
XML格式是通信的标准语言,Android系统也可以通过发送XML文件传输数据.- 我们使用的是用HTML的方式传输文件,这个方式只能传输一般在5M一下的文件.
- 传输大文件不适合用HTML的方式,传输大文件我们要面向Socket编程.确保程序的稳定性
- 将地址和参数存到byte数组中:byte[] data = params.toString().getBytes();
- 利用Apache的HttpClient实现Android客户端发送实体Entity.
- 以上为直接利用HTTP协议来实现的,其实Android已经集成了,第三方开源项目:
org.apache.http.client.HttpClient,可以直接参考它提供的API使用。
HTTP clients encapsulate a smorgasbord of objects required to execute HTTP requests while handling cookies, authentication, connection management, and other features. Thread safety of HTTP clients depends on the implementation and configuration of the specific client.
使用POST方法进行参数传递时,需要使用NameValuePair来保存要传递的参数。另外,还需要设置所使用的字符集。
其他网络相关
服务器实现心跳机制的两种策略?
网络中的接收和发送数据都是使用SOCKET进行实现。但是如果此套接字已经断开,那发送数据和接收数据的时候就一定会有问题。可是如何判断这个套接字是否还可以使用呢?这个就需要在系统中创建心跳机制。其实TCP中已经为我们实现了一个叫做心跳的机制。
大部分C/S的应用需要心跳机制。心跳机制一般在Server和Client都要实现,两者实现原理基本一样。Client不关心性能,怎么做都行。
如果应用是基于TCP的,可以简单地通过SO_KEEPALIVE实现心跳。TCP在设置的KeepAlive(java中的长连接) 定时器到达时向对端发一个检测TCP segment,如果没收到ACK或RST,尝试几次后,就认为对端已经不存在,最后通知应用程序。这里有个缺点是Server主动发出检测包,对性能有点影响
。
应用自己实现:
- Client启动一个定时器,不断发心跳;
- Server收到心跳后,给个回应;
- Server启动一个定时器,判断Client是否存在,判断方法这里列两种:时间差和简单标志。
时间差策略
- 收到一个心跳后,记录当前时间(记为recvedTime)。
- 判断定时器时间到达,计算多久没收到心跳的时间(T)=当前时间 - recvedTime(上面记录的时间)。如果T大于某个设定值,就可以认为Client超时了。
简单标志
- 收到一个心跳后,设置连接标志为true;
- 判断定时器时间到达,查看所有的标志,false的,认为对端超时了;true的将其设成false。
- 上面这种方法比上面简单一些,但检测某个Client是否离线的误差有点大。
native与js互调?
Android WebView控件
在android app 中嵌入网页的形式。
此外,通过webview可以实现HTML <-> Javascript <-> Android Java 交互,例如:
- Javascript调用Java
webview.addJavascriptInterface(Object obj, String interfaceName)
方法,让该方法可以在javascript中被调用;
在Android中创建提供给webview中页面js调用的接口
,并在该接口中添加@JavascriptInterface
注入,表示该方法可以被js掉用,如js调用native关闭activity方法closeThisPage
:
@JavascriptInterfacepublic void closeThisPage(){
//关闭本页面 context.finish();}
- Java中调用Javascript脚本中的方法
调用js的show方法.
webview.loadUrl("javascript:show('"+json+"')");