二、网络编程与网络框架
一、网络分层
1,物理层:
负责物理运输,即把计算机连接起来的物理手段。
2,数据链路层:
控制网络层与物理层间的通信,保证数据在不可靠的物理层准确传输。传输时将数据分割为传输帧李梅包含了原始数据,发送方接收方地址以及纠错和控制信息。
3,网络层:
该层决定如何将数据从发送方路由到接收方,其主要功能是建立主机到主机的通信。
4,传输层:
该层为两个主机上的应用程序提供端到端的通信,传输协议为:TCP可靠的面向连接的协议。UDP不可靠无连接协议。
5,应用层:
应用程序接到传输层的数据后进行解读,解读必须用到事先定好的格式主要协议有:HTTP、FTP、Telent、SMTP、POP3等。
二、TCP三次握手和四次挥手
TCP层FLAGS字段标识:
SYN表示建立连接,FIN表示关闭连接,ACK表示响应,PSH表示有 DATA数据传输,RST表示连接重置。
其中,ACK是能与SYN,FIN等同时使用的,比如SYN和ACK可能同时为1,它表示的就是建立连接之后的响应,如果只是单个的一个SYN,它表示的只是建立连接。TCP的几次握手就是通过这样的ACK表现出来的。SYN与FIN不会同时为1,因为前者表示的是建立连接,而后者表示的是断开连接。RST一般是在FIN之后才会出现为1的情况,表示的是连接重置。一般地,当出现FIN包或RST包时,我们便认为客户端与服务器端断开了连接;而当出现SYN和SYN+ACK包时,我们认为客户端与服务器建立了一个连接。PSH为1的情况,一般只出现在 DATA内容不为0的包中,也就是说PSH为1表示的是有真正的TCP数据包内容被传递。TCP的连接建立和连接关闭,都是通过请求-响应的模式完成的。
三次握手
第一次握手:
建立连接,客户端发送请求连接报文,将SYN设为1,Sequence Number(seq)为x;接下来客户端进入SYN_SENT状态,等待服务器的确认。
第二次握手:
服务器收到客户端的SYN报字段,对其进行确认,设置Acknowledgement Number(ACK)为x+1(seq+1);同时发送自己的SYN请求信息,将SYN设置为1,seq为y,服务端将上述信息放入SYN+ACK报文中一并发给客户端,此时服务端进入SYN_RCVD状态。
第三次握手:
客户端收到服务端的SYN+ACK报文段,将ACK设为y+1,向服务器发送ACK报文段,发送完毕后客户端服务端都进入ESTABLISHED(TCP链接成功)状态,完成TCP三次握手。
四次挥手:
客户端和服务端通过三次握手建立连接,当数据传输完成后断开连接时需要四次挥手。
第一次挥手:
客户端设置seq和ACK向服务端发送FIN报文段,客户端进入FIN_WAIT_1状态,表示客户端没有数据要发给服务端了。
第二次挥手:
服务端收到FIN报文段,向客户端回一个ACK报文段。
第三次挥手:
服务端向客户端发送FIN报文段,请求关闭连接,服务端进入LAST_ACK状态。
第四次挥手:
客户端收到服务端发送的FIN报文段,向服务端发送ACK报文段,客户端进入TIME_WAIT状态。服务端收到ACK报文段后就关闭连接,此时客户端等待2MSL(最大报文生存时间)后依旧没有回复说明服务端已正常关闭,这样客户端也可以关闭了。
如果有大量连接每次连接、关闭都经过三次握手四次挥手会造成性能低下,因此HTTP有一种keepalive connections机制用于保持连接,当客户端需要再次获取数据时可以直接使用刚刚空闲下来的连接而无需再次握手。
三、HTTP协议
简介:
HTTP支持C/S(客户/服务器)模式
简单快速,客户向服务器请求服务时只需要传送请求方法和路径。常用请求方法为GET、POST、HEAD。
灵活,HTTP允许传输任意数据对象,正在传输的类型由Content-Type标记。
无连接,限制每次连接只处理一个请求,服务器处理完客户端请求并收到客户端应答后即断开连接,节省传输时间。
无状态,HTTP协议是无状态的,即不具备存储记忆能力,如果后面处理需要前面的信息则必须重传。
HTTP请求报文:
一般一个HTTP请求报文由请求行、请求报头、空行和请求数据四部分组成。
1,请求行
Method Request-URI HTTP-Version CRLF
Method为请求方法,Request-URI是一个统一资源标识符,HTTP-Version表示HTTP协议版本,CRLF表示回车换行。
HTTP请求方法包括:
GET:请求获取Request-URI所标识的资源。
POST:在Request-URI所标识的资源后附加新的数据。
HEAD:请求获取由Request-URI所标识的资源的响应消息报头。
PUT:请求服务器存储一个资源,并用Request-URI做标识。
DELETE:请求服务器删除Request-URI所标识的资源。
TRACE:请求服务器回送收到的请求信息,主要用于测试诊断。
CONNECT:HTTP1.1协议中预留给能够连接改为管道方式的代理服务器。
OPTIONS:请求查询服务器性能,或者查询与资源相关的选项和需求。
2,请求数据:
请求数据不在GET方法中使用,而在POST方法中使用,与数据相关的常用的请求报头Content-Type和Content-Length。
HTTP响应报文:
响应报文由状态行、响应报头、空行、响应正文组成。
1,状态行:
HTTP-Version Status-Code Reason-Phrase CRLF
HTTP-Version表示服务器HTTP协议版本,Status-Code表示服务器响应码,Reason-Phrase表示状态码文本描述,状态码类别:
100~199:指示信息,收到请求,需要请求者继续执行操作。
200~299:请求成功,请求已被成功接收并处理。
300~399:重定向,要完成请求必须进行进一步操作。
400~499:客户端错误,请求有语法错误或请求无法实现。
500~599:服务器错误,服务器不能实现合法的请求。
HTTP的消息报头:
消息报头由键值对组成,每行一对,键和值用:分隔。
1,通用报头
既可以出现在请求报头,也可以出现在响应报头。
DATA:表示消息产生的时间和日期。
Connection:允许发送指定连接的选项。例如Connection: keep-alive保持连接。
Cache-Control:指定缓存命令。
2,请求报头
用于通知服务器关于客户端的信息。
Host:请求的主机名,允许多个域名同一个IP(虚拟主机)。
User-Agent:发送请求的浏览器类型、操作系统等信息。
Accept:客户端可识别内容类型列表,用于指定客户端接收那些类型信息。
Accept-Encoding:客户端可识别的数据编码。
Accept-Language:浏览器所支持语言。
Connection:允许客户端和服务器指定与请求/响应链接有关的选项。
Transfer-Encoding:告知接收端为了保证报文的可靠传输对报文的编码方式。
3,响应报头
用于服务器传递自身信息的响应。
Location:用于重定向接收者到一个新的位置,常用在更换域名。
Server:对应User-Agent表示服务器用来处理请求的系统信息。
4,实体报头
用来定义被传送资源的信息。
Content-Type:发送给接收者的实体正文的媒体类型。
Content-Length:实体正文的长度。
Content-Language:描述资源所用的自然语言。
Content-Encoding:实体正文的附加内容编码格式。
Last-Modified:用于指示资源的最后修改日期时间。
Expires:响应过期的日期时间。
四、HttpURLConnection
使用HttpURLConnection构建POST请求
URL mUrl = new URL("url");
HttpURLConnection mHttpURLConnection = (HttpURLConnection) mUrl.openConnection();
//设置连接超时时间
mHttpURLConnection.setConnectTimeout(15000);
//设置读取超时时间
mHttpURLConnection.setReadTimeout(15000);
//设置请求参数
mHttpURLConnection.setRequestMethod("POST");
//添加Header
mHttpURLConnection.setRequestProperty("Connection","Keep-Alive");
//接收输入流
mHttpURLConnection.setDoInput(true);
//传递参数时开启
mHttpURLConnection.setDoOutput(true);
//添加请求参数
StringBuilder mBuilder = new StringBuilder();
mBuilder.append(URLEncoder.encode("lastId","UTF-8"));
mBuilder.append("=");
mBuilder.append(URLEncoder.encode("111110","UTF-8"));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(mHttpURLConnection.getOutputStream(),"UTF-8"));
writer.write(mBuilder.toString());
writer.flush();
writer.close();
//发送请求
mHttpURLConnection.connect();
//获取输入流
InputStream inputStream = mHttpURLConnection.getInputStream();
//获取状态码
int code = mHttpURLConnection.getResponseCode();
//请求结果
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuffer stringBuffer = new StringBuffer();
String line = null;
while ((line=reader.readLine())!=null){
stringBuffer.append(line);
}
String response = stringBuffer.toString();
inputStream.close();
五、OKHTTP3
1,基本用法
配置gradle
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
2,创建GET请求
Request.Builder builder = new Request.Builder().url("http://www.baidu.com");
builder.method("GET",null);
Request request = builder.build();
OkHttpClient okHttpClient = new OkHttpClient();
Call call = okHttpClient.newCall(request);
//异步请求
call.enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
String str = response.body().string();
}
});
//同步请求
try {
Response response = call.execute();
String str = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
3,创建POST请求
RequestBody requestBody = new FormBody.Builder()
.add("name","xiyang")
.build();
Request request = new Request.Builder()
.url("http://www.baidu.com")
.post(requestBody)
.build();
OkHttpClient okHttpClient = new OkHttpClient();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
String str = response.body().string();
}
});
4,上传文件test.txt
MediaType type = MediaType.parse("text/x-markdown;charset=utf-8");
String filePatch = Environment.getDataDirectory().getAbsolutePath();
File file = new File(filePatch,"test.txt");
Request request = new Request.Builder()
.url("http://www.baidu.com")
.post(RequestBody.create(file,type))
.build();
//如果需要其他参数使用
Request request = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("name","xing")
.addFormDataPart("image","text.txt",RequestBody.create(file,type))
.build();
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
}
});
5,下载图片文件
String filePatch = Environment.getDataDirectory().getAbsolutePath();
String pigUrl = "http://www.baidu.com/css.jpg";
Request request = new Request.Builder()
.url(pigUrl)
.build();
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
InputStream inputStream = response.body().byteStream();
File file = new File(filePatch,"css.jpg");
FileOutputStream fileOutputStream = new FileOutputStream(file);
byte[] bytes = new byte[2048];
int len = 0;
while ((len = inputStream.read(bytes))!=-1){
fileOutputStream.write(bytes);
}
fileOutputStream.flush();
}
});
6,设置超时时间和缓存
File sdCache = getExternalCacheDir();
int cacheSize = 10*1024*1024;
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.MICROSECONDS)
.writeTimeout(15, TimeUnit.MICROSECONDS)
.readTimeout(15, TimeUnit.MICROSECONDS)
.cache(new Cache(sdCache.getAbsoluteFile(),cacheSize))
.build();
7,取消请求
call.cancel()可以立即停止一个正在执行的call,当用户离开应用或者跳转其他页面时可以使用cancel方法停止请求网络。还可以通过tag取消多个请求,创建Request.Builder.tag(Object tag)来分配标签,之后使用OkHttpClient.cancel(tag)取消所有带tag的请求。