TCP/IP五层模型
分层(由上至下) | 作用 | 代表协议 |
---|---|---|
应用层 | 定义报文类型、字段语义 等 | HTTP、SMTP等 |
传输层 | 负责进程之间的通信 | TCP、UDP |
网络层 | 负责子网之间的通信、路由寻址(网络地址) | IP |
链路层 | 定义数据的分组格式、MAC寻址(网卡寻址) | |
物理层 | 将数据编码为用0、1标识的比特流 |
- 下层为上层提供服务
- 在发送端,下层封装上层的数据;在接收端,上层解封装下层的数据
TCP和UDP
TCP:面向连接、可靠的传输方式;3次招手+4次挥手;慢
UDP:不面向连接、不可靠;快
HTTP概述
- 定义了WEB服务器和WEB客户端(浏览器)之间的交互方式
- 使用TCP作为运输层支撑协议
- 无状态协议,即服务器不保存客户端的任何信息
- 1.0及1.0之前为非持续连接;1.1及之后为持续连接
Blockquote
非持续连接:为每一个请求的对象建立一个全新的连接,每个连接都有打开-关闭动作;
持续连接:连接持续打开一段时间,多个对象可复用同一条连接
HTTP报文结构
请求报文
响应报文
Cookie技术
作用:识别和跟踪用户
实现:
1) 客户端首次访问服务器,响应报文首部行包含Set-cookie:1678
2) 客户端将cookie信息保存在自己的cookie文件中
3) 客户端再次向服务器发送请求,请求报文首部行添加Cookie:1678
4) 服务器识别cookie,跟踪和记录客户端访问的顺序及时间等
代理服务器
作用:
1)提高访问速度
2)隐藏真实IP
3)过滤用户
代理协议:HTTP、SOCKS
条件Get
作用:避免服务器响应内容过时和节省带宽
实现:
1)客户端向服务器发送请求
GET /a.html HTTP/1.1
2)服务器返回:
Last-Modified: Thu, 22 Nov 2011 21:00:51 GMT
3)客户端下次请求同一对象:
GET /a.html HTTP/1.1
Host: www.hongchangfirst.com
If-Modified-Since: Thu, 22 Nov 2011 21:00:51 GMT
4)如果有更新,返回
HTTP/1.1 200 OK
Server: hongchangfirst server
Content-Type: text/html; charset=utf-8
Last-Modified: Thu, 28 Nov 2011 21:00:51 GMT
Content-Length: 14
<...实体体...>
如果未更新,返回(而不返回实体体)
HTTP/1.1 304 Not Modified
OkHttp用法
1)构建OkHttpClient
2)构建Request
3)将得到的Request封装为Call,调用Call的enqueue/execute方法
4)在Callback中处理返回的Response
OkHttpClient mOkHttpClient = new OkHttpClient();
//RequestBody requestBody = new FormBody.Builder().add("k1", "v1").add("k2", "v2").build();
Request request = new Request.Builder().url(url).post(requestBody).build();
Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
MyLogUtil.d(TAG, "get, onFailure");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
try {
String result = response.body().string();
MyLogUtil.d(TAG, "get, response=" + result);
} catch (Exception e){
e.printStackTrace();
MyLogUtil.d(TAG, "get, e=", e);
} finally {
if (response != null) {
response.close();
}
}
}
});
主要类介绍
OkHttpClient
- 可指定缓存路径
java
public Builder cache(@Nullable Cache cache) {
this.cache = cache;
this.internalCache = null;
return this;
}
指定代理服务器
public Builder proxy(@Nullable Proxy proxy) { this.proxy = proxy; return this; }
指定读、写以及连接超时时间
将Request封装为Call
@Override public Call newCall(Request request) { return RealCall.newRealCall(this, request, false /* for web socket */); }
Request
HTTP中“请求”的描述
- 封装了Url、头部、实体体、方法类型
java
public final class Request {
final HttpUrl url;
final String method;
final Headers headers;
final @Nullable RequestBody body;
final Object tag;
...
}
Call/RealCall
- Http中“任务”的描述
- 提供了同步(excute)和异步(enqueue)两种执行方式
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
Dispatcher
- 将“请求”交给所维护的线程池执行
- 任务调度
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
AsyncCall
- RealCall的内部类,每个AsyncCall唯一对应一个RealCall
- 实现了Runnable,在run()中回调自己的execute()方法
- 通过getResponseWithInterceptorChain()拿到Response
@Override protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}
Response
- Http中“响应”的描述
- 封装了状态码、响应头以及实体体(ResponseBody)
- networkResponse、cacheResponse
public final class Response implements Closeable {
final Request request;
final Protocol protocol;
final int code;
final String message;
final @Nullable Handshake handshake;
final Headers headers;
final @Nullable ResponseBody body;
final @Nullable Response networkResponse;
final @Nullable Response cacheResponse;
...
}
拦截器链-Interceptor.Chain
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
- 依次构建Interceptor对象,并依次放入ArrayList中
- 调用Interceptor.Chain的proceed方法,使interceptors依次工作
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
...
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
...
}
- 创建下一个拦截链。传入index + 1使得下一个拦截器链只能从下一个拦截器开始访问
执行索引为index的拦截器的intercept方法,并将下一个拦截器链传入该方法
拦截器Interceptor
- 在发起请求前对request进行处理
- 调用下一个拦截器,获取response
- 对response进行处理,返回给上一个拦截器
执行顺序及作用概述
- RetryAndFollowUpInterceptor:失败重连、连接复用
- BridgeInterceptor:设置其他报头,如User-Agent,Host,Keep-alive;添加cookie;设置gzip压缩,并在接收到内容后进行解压
- CacheInterceptor:决定是请求服务器还是返回cache;对cache进行增删查改
- ConnectIntercetot:为当前请求找到一条连接,可能复用也可能重新创建
- CallServerInterceptor:向服务器发起请求,并读取服务器响应
流程框架
任务调度
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
如果满足条件:
- 当前请求数小于最大请求数(64)
- 对单一host的请求小于阈值(5)
将该任务插入正在执行任务队列(runningAsyncCalls),并执行对应任务。如果不满足则将其放入待执行队列(readyAsyncCalls)。
@Override protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
if (promoteCalls) promoteCalls();
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
- 空闲出多余线程,调用promoteCalls调用待执行的任务
如果当前整个线程池都空闲下来,执行空闲通知回调线程(idleCallback)
private void promoteCalls() { if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity. if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote. for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) { AsyncCall call = i.next(); if (runningCallsForHost(call) < maxRequestsPerHost) { i.remove(); runningAsyncCalls.add(call); executorService().execute(call); } if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity. } }
当线程池有空闲时,从readyAsyncCalls取出“适量”的任务加入到runningAsyncCalls,并通过线程池执行。