网络编程梳理:Android网络基础知识复习
本博客为原创 http://www.cnblogs.com/wondertwo/p/5744872.html 未经许可不得转载
0x00 Http请求及其含义
- GET:请求获取Request-URI所标识的资源;
- POST:在Request-URI所标识的资源后附加新数据;
- PUT:请求服务器存储一个资源,并用Request-URI作为其标识;
- DELETE:请求服务器删除Request-URI标识的资源;
- OPTIONS:请求查询服务器的性能,或者查询与资源相关的选项和需求;
- HEAD:请求获取由Request-URI所标识的资源的响应消息头;
- TEACE:请求服务器回送收到的请求消息,主要用于测试和诊断;
- CONNECT:保留关键字,将来使用;
0x01 TCP/IP 4层模型
- 应用层:在应用层中,数据以应用内部使用的格式进行传送,然后被编码成标准协议的格式,比如万维网的HTTP协议、接收电子邮件使用的POP3和IMAP协议、发送邮件使用的SMTP协议、文件传输使用的FTP协议,以及远程登录使用的SSH和Telnet等。所以用户通常至于应用层进行交互;
- 传输层:响应来自应用层的服务请求,并向网络层发出服务请求。传输层提供两台主机之间透明的数据传输,通常用于端到端连接、流量控制或错误恢复。这层最重要的两个协议是TCP(Transmission Control Protocol,传输控制协议)和UDP(User Datagram protocol,用户数据报协议);
- 网络层:网络层提供端到端的数据包交付,负责数据包从源发送到目的地,任务包括网络路由,差错控制,IP编址等。这层包括的重要协议有:IP(IPv4,IPv6)、ICMP(Internet Message Control,Internet控制报文协议)、IPSec(Internet Protocol Security,Internet协议安全);
- 网络接口层:负责通过主机发送和接收IP数据报;允许主机连入网络时使用多种现成流行的技术,比如以太网、令牌网、帧中继、ATM、X.25、DDN、SDH、WDM等。
下图是传统七层模型与TCP四层模型的对比
一个工程应用一般都会使用到两个传输层协议之一:面向连接的TCP传输控制协议和面向无连接的UDP用户数据报协议。
TCP协议
传输控制协议(Transmission Control Protocol, TCP),是一种面向连接的、可靠地、基于字节流的传输层通信协议。在保证可靠性的基础上,采用超时重传和稍待确认机制,在酒量控制上,采用滑动窗口协议,协议中规定,对于窗口内未经确认的分组需要重传;在拥塞控制上,采用慢启动算法。原理如下图:
TCP和UDP的区别
TCP和UDP在传输过程冲的具体实现方法不同,两者都接收传输协议数据包并将其内容向前传输到应用层。TCP把消息分解成数据包,并在接收端以正确的顺序把他们重新装配起来,TCP还处理对遗失数据包的重传请求,位于上层的应用层要处理的事情就少多了。UDP不提供装配和重传请求这些功能,它只是向前喜欢送数据包。位于上层的应用层必须确保消息是完整的。并且是以正确的顺序装配的。
0x02 Socket套接字
一台服务器可能会提供多种服务,每服务都对应一个Socket(可以吧Socket理解为一个插座,客户需要哪种服务,就把插头插到服务对应的插座上);用户的插头也是一个Socket。Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。Socket把复杂的TCP/IP协议隐藏在Socket接口后面,对用户来说,一组简单的Socket接口就是全部,Socket会组织数据,已符合指定的协议。Socket用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过套接字向网络发出请求或者应答网络的请求。Socket的基本操作包括:
- 连接远程机;
- 发送数据;
- 接收数据;
- 关闭连接;
- 绑定端口;
- 监听到大数据;
- 在绑定的端口上接受来自远程机器的连接;
java.net 包下提供了 ServerSocket 和 Socket 两个类,前者用于客户端可以实现连接远程服务器,发送数据,接收数据,关闭连接等,服务器端Socket还要实现绑定端口,监听到达数据,接收来自远程机器的连接。
客户端 Socket 有如下几个构造方法
有如下几个成员方法
- public InputStream getInputStream():读出该Socket数据
- public OutputStream getOutputStream():向该Socket写入数据
- public synchronized void close():关闭该Socket
服务端 ServerSocket 的构造方法如下:
有如下几个重要的重要的成员方法
构造完ServerSocket之后,需要调用ServerSocket.accept()方法来等待客户端的请求(因为Socket是绑定在端口上面的,所以知道是哪个客户端请求的),accept()方法会返回请求这个服务的客户端的Socket实例,然后调用这个Socket实例的相应的方法,操作传输过来的数据信息,当这个Socket实例操作完毕后,调用close()方法将其关闭。
0x03 TCP的C/S通信模型
TCP服务端工作步骤如下:
- 调用ServerSocket(int port) 创建一个ServerSocket,并绑定到指定端口上;
- 调用accept()方法监听连接请求,如果客户端请求连接,则接受连接并返回通信套接字Socket;
- 调用Socket类的getOutputStream()和getInoputStream()方法获取输入流和输出流,开始网络数据的发送和接收;
- 关闭通信Socket;
// 创建一个ServerSocket对象
ServerSocket serverSocket = null;
try {
// TCP_SERVICE_PORT为指定端口号,为int类型
serverSocket = new ServerSocket(TCP_SERVICE_PORT);
// 监听连接请求
Socket socket = serverSocket.accept();
// 开始读写
BufferedReader in = new BufferedReader(new InputStream(socket.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStream(socket.getOutputStream()));
// 读取接收信息,转换为字符串
String incomingMsg = in.readLine() + System.getProperty("line.separator");
// 生成发送字符串
String outgoingMsg = "goodbye from port " + TCP_SERVICE_PORT + System.getProperty("line.separator");
out.write(outgoingMsg);
// 刷新发送
out.flush();
// 关闭
socket.close();
} catch (InterruptedIOException e) { // 超时异常
e.printStackTrace();
} catch (IOException e) { // IO异常
e.printStackTrace();
} finally {
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
TCP客户端工作步骤如下:
- 调用Socket()创建一个流套接字,并连接到服务器;
- 调用Socket类的getOutputStream()方法和getInputStream()方法获取输出和输入流,开始网络数据的发送和接收;
- 关闭通信套接字;
try {
// 初始化Socket,TCP_SERVICE_PORT为指定端口号,为int类型
Socket socket = new Socket(TCP_SERVICE_PORT);
// 生成输出流
BuffereedReader in = new BufferedReader(new InputStream(socket.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStream(socket.getOutputStream()));
// 读取接收信息,转换为字符串
String incomingMsg = in.readLine() + System.getProperty("line.separator");
// 生成发送字符串
String outMsg = "TCP connected to " + TCP_SERVICE_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) { // IO异常
e.printStackTrace();
}
以上步骤需要注意
- 无论是客户端还是服务端,都要添加 UnknownHostException,来处理网络异常;添加 IOException 来处IO异常;
- 需要在Android客户端清单文件中添加网络权限:
<uses-permision android:name="android.permission.INTERNET" />
0x04 关于Apache HttpClient
简单来说,Apache HttpClient就是一个增强版的HttpURLConnection,HttpURLConnection的所有功能都能实现,不同点是它更加关注于如何发送请求、接收响应、以及管理HTTP连接。使用HttpClient发送请求、接收响应很简单,只需如下几步:
- 创建HttpClient对象;
- 如果需要发送GET请求,则创建HttpGet对象,如果需要发送POST请求,则常见HttpPost对象;
- 如果需要发送请求参数,则可调用HttpGet、HttpPost共同的setParams(HttpParams params)方法来添加请求参数;对于HttPost对象而言,也可调用setEntity(HttpEntity entity)方法来设置请求参数;
- 调用HttpClient对象的excute(HttpUriReuest request)等方法发送请求,执行该方法返回一个HttpResponse;
- 抵用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可以获取服务器的响应头;调用HttpResponse的getEntity()方法可以获取HttpEntity对象,该对象包装了服务器的响应内容,程序可通过该对象获取服务器的响应内容;
在Android6.0+谷歌官方api移除了对HttpClient的支持,如果要使用HttpClient,可在moudle的build.gradle文件中添加如下库依赖即可:
android {
...
useLibrary 'org.apache.http.legacy'
}
URLConnection访问网络
在很多情况下,需要保存用户浏览过的网络页面,实现这个功能:通过网址生成URL对象,然后打开链接,写入buffer,最后写入字符串中。实现代码如下:
try {
URL newUrl = new URL("http://translate.google.com");
URLConnection connect = newUrl.openConnection();
DataInputStream dis = new DataInputStream(connect.getInputStream());
BufferedReader in = new BufferedReader(new InputStream(dis, "UTF-8"));
String html = "";
String readLine = null;
while ((readLine = in.readLine()) != null) {
html = html + readLine;
Log.d("OpenWebviewActivity", readLine);
}
in.close();
} catch (MalformedURLException me) {
} catch (IOException ioe) {
}