@Override
public void enqueue(Callback responseCallback) {
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
}
```
}
}
}
}
//第二种
public final class StreamAllocation {
public void streamFinished(boolean noNewStreams, HttpCodec codec, long bytesRead, IOException e) {
...
if (e != null) {
eventListener.callFailed(call, e);
} else if (callEnd) {
eventListener.callEnd(call);
}
...
}
}
```
- callEnd也有两种调用场景。第一种也是在关闭流时。第二种是在释放连接时。
``` java
public final class StreamAllocation {
public void streamFinished(boolean noNewStreams, HttpCodec codec, long bytesRead, IOException e) {
...
if (e != null) {
eventListener.callFailed(call, e);
} else if (callEnd) {
eventListener.callEnd(call);
}
...
}
public void release() {
...
if (releasedConnection != null) {
eventListener.connectionReleased(call, releasedConnection);
eventListener.callEnd(call);
}
}
}
```
- 为什么会将关闭流和关闭连接区分开?
- 在http2版本中,一个连接上允许打开多个流,OkHttp使用StreamAllocation来作为流和连接的桥梁。当一个流被关闭时,要检查这条连接上还有没有其他流,如果没有其他流了,则可以将连接关闭了。
- streamFinished和release作用是一样的,都是关闭当前流,并检查是否需要关闭连接。不同的是,当调用者手动取消请求时,调用的是release方法,并由调用者负责关闭请求输出流和响应输入流。
// Try each address for best behavior in mixed IPv4/IPv6 environments.
List<InetAddress> addresses = address.dns().lookup(socketHost);
if (addresses.isEmpty()) {
throw new UnknownHostException(address.dns() + " returned no addresses for " + socketHost);
}
eventListener.dnsEnd(call, socketHost, addresses);
}
}
```
public StreamAllocation(ConnectionPool connectionPool, Address address, Call call,
EventListener eventListener, Object callStackTrace) {
this.routeSelector = new RouteSelector(address, routeDatabase(), call, eventListener);
}
}
```
rawSocket = proxy.type() == Proxy.Type.DIRECT || proxy.type() == Proxy.Type.HTTP
? address.socketFactory().createSocket()
: new Socket(proxy);
eventListener.connectStart(call, route.socketAddress(), proxy);
}
```
private void connectTunnel(int connectTimeout, int readTimeout, int writeTimeout, Call call,
EventListener eventListener) throws IOException {
Request tunnelRequest = createTunnelRequest();
HttpUrl url = tunnelRequest.url();
for (int i = 0; i < MAX_TUNNEL_ATTEMPTS; i++) {
connectSocket(connectTimeout, readTimeout, call, eventListener);
eventListener.connectEnd(call, route.socketAddress(), route.proxy(), null);
}
}
```
eventListener.secureConnectStart(call);
connectTls(connectionSpecSelector);
eventListener.secureConnectEnd(call, handshake);
}
```
if (releasedConnection != null) {
eventListener.connectionReleased(call, releasedConnection);
}
if (foundPooledConnection) {
eventListener.connectionAcquired(call, result);
}
synchronized (connectionPool) {
if (canceled) throw new IOException("Canceled");
if (newRouteSelection) {
//第二次查缓存
List<Route> routes = routeSelection.getAll();
for (int i = 0, size = routes.size(); i < size; i++) {
Route route = routes.get(i);
Internal.instance.get(connectionPool, address, this, route);
if (connection != null) {
foundPooledConnection = true;
result = connection;
this.route = route;
break;
}
}
}
if (!foundPooledConnection) {
//如果缓存没有,则新建连接
route = selectedRoute;
refusedStreamCount = 0;
result = new RealConnection(connectionPool, selectedRoute);
acquire(result, false);
}
}
// If we found a pooled connection on the 2nd time around, we're done.
if (foundPooledConnection) {
eventListener.connectionAcquired(call, result);
return result;
}
// Do TCP + TLS handshakes. This is a blocking operation.
result.connect(connectTimeout, readTimeout, writeTimeout, pingIntervalMillis,
connectionRetryEnabled, call, eventListener);
routeDatabase().connected(result.route());
eventListener.connectionAcquired(call, result);
return result;
}
```
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
HttpCodec httpCodec = realChain.httpStream();
StreamAllocation streamAllocation = realChain.streamAllocation();
RealConnection connection = (RealConnection) realChain.connection();
Request request = realChain.request();
long sentRequestMillis = System.currentTimeMillis();
realChain.eventListener().requestHeadersStart(realChain.call());
httpCodec.writeRequestHeaders(request);
realChain.eventListener().requestHeadersEnd(realChain.call(), request);
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
if (responseBuilder == null) {
// Write the request body if the "Expect: 100-continue" expectation was met.
realChain.eventListener().requestBodyStart(realChain.call());
long contentLength = request.body().contentLength();
CountingSink requestBodyOut =
new CountingSink(httpCodec.createRequestBody(request, contentLength));
BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();
realChain.eventListener().requestBodyEnd(realChain.call(), requestBodyOut.successfulCount);
}
}
return response;
}
}
```
@Override public Response intercept(Chain chain) throws IOException {
Response.Builder responseBuilder = null;
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
httpCodec.flushRequest();
realChain.eventListener().responseHeadersStart(realChain.call());
responseBuilder = httpCodec.readResponseHeaders(true);
}
}
httpCodec.finishRequest();
if (responseBuilder == null) {
realChain.eventListener().responseHeadersStart(realChain.call());
responseBuilder = httpCodec.readResponseHeaders(false);
}
int code = response.code();
if (code == 100) {
// server sent a 100-continue even though we did not request one.
// try again to read the actual response
responseBuilder = httpCodec.readResponseHeaders(false);
response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
code = response.code();
}
realChain.eventListener() .responseHeadersEnd(realChain.call(), response);
return response;
}
}
```
@Override public ResponseBody openResponseBody(Response response) throws IOException {
streamAllocation.eventListener.responseBodyStart(streamAllocation.call);
String contentType = response.header("Content-Type");
if (!HttpHeaders.hasBody(response)) {
Source source = newFixedLengthSource(0);
return new RealResponseBody(contentType, 0, Okio.buffer(source));
}
if ("chunked".equalsIgnoreCase(response.header("Transfer-Encoding"))) {
Source source = newChunkedSource(response.request().url());
return new RealResponseBody(contentType, -1L, Okio.buffer(source));
}
long contentLength = HttpHeaders.contentLength(response);
if (contentLength != -1) {
Source source = newFixedLengthSource(contentLength);
return new RealResponseBody(contentType, contentLength, Okio.buffer(source));
}
return new RealResponseBody(contentType, -1L, Okio.buffer(newUnknownLengthSource()));
}
}
```
private static final String TAG = "NetworkEventListener";
private static AtomicInteger mNextRequestId = new AtomicInteger(0);
private String mRequestId ;
public static Factory get(){
Factory factory = new Factory() {
@NotNull
@Override
public EventListener create(@NotNull Call call) {
return new NetworkListener();
}
};
return factory;
}
@Override
public void callStart(@NotNull Call call) {
super.callStart(call);
//mRequestId = mNextRequestId.getAndIncrement() + "";
//getAndAdd,在多线程下使用cas保证原子性
mRequestId = String.valueOf(mNextRequestId.getAndIncrement());
ToolLogUtils.i(TAG+"-------callStart---requestId-----"+mRequestId);
saveEvent(NetworkTraceBean.CALL_START);
saveUrl(call.request().url().toString());
}
@Override
public void dnsStart(@NotNull Call call, @NotNull String domainName) {
super.dnsStart(call, domainName);
ToolLogUtils.d(TAG, "dnsStart");
saveEvent(NetworkTraceBean.DNS_START);
}
@Override
public void dnsEnd(@NotNull Call call, @NotNull String domainName, @NotNull List<InetAddress> inetAddressList) {
super.dnsEnd(call, domainName, inetAddressList);
ToolLogUtils.d(TAG, "dnsEnd");
saveEvent(NetworkTraceBean.DNS_END);
}
@Override
public void connectStart(@NotNull Call call, @NotNull InetSocketAddress inetSocketAddress, @NotNull Proxy proxy) {
super.connectStart(call, inetSocketAddress, proxy);
ToolLogUtils.d(TAG, "connectStart");
saveEvent(NetworkTraceBean.CONNECT_START);
}
@Override
public void secureConnectStart(@NotNull Call call) {
super.secureConnectStart(call);
ToolLogUtils.d(TAG, "secureConnectStart");
saveEvent(NetworkTraceBean.SECURE_CONNECT_START);
}
@Override
public void secureConnectEnd(@NotNull Call call, @Nullable Handshake handshake) {
super.secureConnectEnd(call, handshake);
ToolLogUtils.d(TAG, "secureConnectEnd");
saveEvent(NetworkTraceBean.SECURE_CONNECT_END);
}
@Override
public void connectEnd(@NotNull Call call, @NotNull InetSocketAddress inetSocketAddress,
@NotNull Proxy proxy, @Nullable Protocol protocol) {
super.connectEnd(call, inetSocketAddress, proxy, protocol);
ToolLogUtils.d(TAG, "connectEnd");
saveEvent(NetworkTraceBean.CONNECT_END);
}
@Override
public void connectFailed(@NotNull Call call, @NotNull InetSocketAddress inetSocketAddress, @NotNull Proxy proxy, @Nullable Protocol protocol, @NotNull IOException ioe) {
super.connectFailed(call, inetSocketAddress, proxy, protocol, ioe);
ToolLogUtils.d(TAG, "connectFailed");
}
@Override
public void requestHeadersStart(@NotNull Call call) {
super.requestHeadersStart(call);
ToolLogUtils.d(TAG, "requestHeadersStart");
saveEvent(NetworkTraceBean.REQUEST_HEADERS_START);
}
@Override
public void requestHeadersEnd(@NotNull Call call, @NotNull Request request) {
super.requestHeadersEnd(call, request);
ToolLogUtils.d(TAG, "requestHeadersEnd");
saveEvent(NetworkTraceBean.REQUEST_HEADERS_END);
}
@Override
public void requestBodyStart(@NotNull Call call) {
super.requestBodyStart(call);
ToolLogUtils.d(TAG, "requestBodyStart");
saveEvent(NetworkTraceBean.REQUEST_BODY_START);
}
@Override
public void requestBodyEnd(@NotNull Call call, long byteCount) {
super.requestBodyEnd(call, byteCount);
ToolLogUtils.d(TAG, "requestBodyEnd");
saveEvent(NetworkTraceBean.REQUEST_BODY_END);
}
@Override
public void responseHeadersStart(@NotNull Call call) {
super.responseHeadersStart(call);
ToolLogUtils.d(TAG, "responseHeadersStart");
saveEvent(NetworkTraceBean.RESPONSE_HEADERS_START);
}
@Override
public void responseHeadersEnd(@NotNull Call call, @NotNull Response response) {
super.responseHeadersEnd(call, response);
ToolLogUtils.d(TAG, "responseHeadersEnd");
saveEvent(NetworkTraceBean.RESPONSE_HEADERS_END);
}
@Override
public void responseBodyStart(@NotNull Call call) {
super.responseBodyStart(call);
ToolLogUtils.d(TAG, "responseBodyStart");
saveEvent(NetworkTraceBean.RESPONSE_BODY_START);
}
@Override
public void responseBodyEnd(@NotNull Call call, long byteCount) {
super.responseBodyEnd(call, byteCount);
ToolLogUtils.d(TAG, "responseBodyEnd");
saveEvent(NetworkTraceBean.RESPONSE_BODY_END);
}
@Override
public void callEnd(@NotNull Call call) {
super.callEnd(call);
ToolLogUtils.d(TAG, "callEnd");
saveEvent(NetworkTraceBean.CALL_END);
generateTraceData();
NetWorkUtils.timeoutChecker(mRequestId);
}
@Override
public void callFailed(@NotNull Call call, @NotNull IOException ioe) {
super.callFailed(call, ioe);
ToolLogUtils.d(TAG, "callFailed");
}
private void generateTraceData(){
NetworkTraceBean traceModel = IDataPoolHandleImpl.getInstance().getNetworkTraceModel(mRequestId);
Map<String, Long> eventsTimeMap = traceModel.getNetworkEventsMap();
Map<String, Long> traceList = traceModel.getTraceItemList();
traceList.put(NetworkTraceBean.TRACE_NAME_TOTAL,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.CALL_START, NetworkTraceBean.CALL_END));
traceList.put(NetworkTraceBean.TRACE_NAME_DNS,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.DNS_START, NetworkTraceBean.DNS_END));
traceList.put(NetworkTraceBean.TRACE_NAME_SECURE_CONNECT,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.SECURE_CONNECT_START, NetworkTraceBean.SECURE_CONNECT_END));
traceList.put(NetworkTraceBean.TRACE_NAME_CONNECT,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.CONNECT_START, NetworkTraceBean.CONNECT_END));
traceList.put(NetworkTraceBean.TRACE_NAME_REQUEST_HEADERS,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.REQUEST_HEADERS_START, NetworkTraceBean.REQUEST_HEADERS_END));
traceList.put(NetworkTraceBean.TRACE_NAME_REQUEST_BODY,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.REQUEST_BODY_START, NetworkTraceBean.REQUEST_BODY_END));
traceList.put(NetworkTraceBean.TRACE_NAME_RESPONSE_HEADERS,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.RESPONSE_HEADERS_START, NetworkTraceBean.RESPONSE_HEADERS_END));
traceList.put(NetworkTraceBean.TRACE_NAME_RESPONSE_BODY,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.RESPONSE_BODY_START, NetworkTraceBean.RESPONSE_BODY_END));
}
private void saveEvent(String eventName){
NetworkTraceBean networkTraceModel = IDataPoolHandleImpl.getInstance().getNetworkTraceModel(mRequestId);
Map<String, Long> networkEventsMap = networkTraceModel.getNetworkEventsMap();
networkEventsMap.put(eventName, SystemClock.elapsedRealtime());
}
private void saveUrl(String url){
NetworkTraceBean networkTraceModel = IDataPoolHandleImpl.getInstance().getNetworkTraceModel(mRequestId);
networkTraceModel.setUrl(url);
}
}
```
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。