1. TCP three-way handshake

The TCP three-way handshake prevents invalid connection requests from suddenly arriving. Let’s take an example of why you need to shake hands three times instead of twice.

Let’s imagine this scene. Xiao Ming goes to a restaurant for dinner. He arrives late and it’s past dinner time.

  • The first handshake, because it has passed the meal, so Xiao Ming needs to ask wang Xiaoer, the waiter, please ask the boss you are still closed, Wang Xiaoer turned around to ask the boss, this is the first handshake;
  • The second time shake hands, the boss listen to, ah although this is over the meal point but rich who does not earn ah, tell Wang Xiaoer and Xiao Ming said normal business;
  • The third handshake: Wang Xiaoer told Xiao Ming normal business, then Xiao Ming said good I began to order now, and then the boss informed the kitchen waiting for cooking, Xiao Ming said I want to eat braised fish, potato chips, so this deal became;

Same scene above, let’s change the details a little bit

  • For the first time, Ming still needs Wang Xiaoer to ask the boss about the business is not open, Wang Xiaoer received an emergency phone call on the way to ask the boss, patronize the phone after an hour just remembered that there is a customer Xiao Ming, this time just rushed to ask the boss;
  • The second handshake: the same as above, the boss still think that money is earned, tell Wang Xiao er to tell Xiao Ming that normal business;
  • The third handshake: Wang Xiaoer got a reply hurriedly ran to tell Xiao Ming, who knows the time is too long Xiao Ming can’t wait to go, well since the customer left, then everyone off work, the chef need not wait;

If is two shake hands, not the third step, the boss whether xiaoming also is in the shop in the second handshake would wait inform chef to cook, cook estimate is not order such a long time, it’s not a waste of resources, it can go home happy, so the key of the three-way handshake is, whether it can strain connection requests invalidation.


2. TCP wave four times

TCP requires disconnection to follow the four-wave principle, so we’re going to drop the jargon and just describe the four-wave process, and we’re going to use the three-way handshake as an example of ordering food.

After three handshakes, Xiao Ming began to order. When the order was finished, this scene appeared:

  • The first wave, Xiao Ming told the boss, my food is finished, we do not need to keep communicating;
  • The second wave, the boss told Xiao Ming, “Well, I know you have ordered the food, but we have not finished the food you ordered before, so we have to keep in touch with each other for the time being, you can wait at ease.
  • The third wave, the cook finished the dishes, the boss told Xiao Ming we finished the dishes for you, we do not need to communicate;
  • The fourth wave, Xiao Ming said that is it, do not need to communicate, xiao Ming and so on for a while the boss did not respond, Xiao Ming will know that everyone off work, I began to have a good meal.

3. Source code process analysis of okHTTP synchronization request

For okHTTP synchronization requests, we clearly know this usage:

OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
    .url("http://www.baidu.com")
    .build();
Response response = client.newCall(request).execute(a);Copy the code

We can see that the execute() method is called. Let’s break it down:

Step1 first calls OkHttpClient’s newCall() method to generate an interface Call;

RealCall is the implementation class of Call, so the synchronous request actually calls the execute() method of RealCall.

@Override 
public Call newCall(Request request) {
    return new RealCall(this, request, false);
}Copy the code

Client.dispatcher ().executed(this); In fact, the execute() method of RealCall finally executed() of the client.dispatcher() method. Client.dispatcher () is a Dispatcher object.

@Override 
public Response execute(a)throws IOException {
  captureCallStackTrace();
  try {
    client.dispatcher().executed(this);
    Response result = getResponseWithInterceptorChain();
    if (result == null) throw new IOException("Canceled");
    return result;
  } finally {
    client.dispatcher().finished(this); }}Copy the code

What is the Step4 Dispatcher class? Its name, “Dispatcher,” and a set of parameters give you an idea of what to do with each request.

private int maxRequests = 64;
private int maxRequestsPerHost = 5;
private Runnable idleCallback;
ExecutorService executorService;
Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
Deque<RealCall> runningSyncCalls = new ArrayDeque<>();Copy the code

For synchronous requests, it ends up calling the Executed () method of the Dispatcher class.

synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
}Copy the code

As you can see, we put the Call task in a queue. This queue will be called somewhere outside to perform the request. When a call request task is completed, the finished() method of the Dispatcher class will be called. The finished() method checks to see if any requests still need to be executed.


4. Okhttp asynchronous request source code process analysis

The OKhttp asynchronous network request is basically the same as the first three steps of the synchronous network request, except that the synchronous request calls the execute() method and the asynchronous call enqueue() method.

Step1, Step2, Step3 omit…

Step4

In synchronous cases, we can add the task to the executing queue anyway, but in asynchronous cases, we need to consider the maximum number of concurrent requests, so we need to use two criteria to determine if we have reached a point where we can execute immediately. OKhttp uses no more than 64 concurrent requests and no more than 5 accesses to the same address to indicate immediate execution into the thread pool.

synchronized void enqueue(AsyncCall call) {
  if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
    runningAsyncCalls.add(call);
    executorService().execute(call);
  } else {
    readyAsyncCalls.add(call);}}Copy the code

Step5 here we have two cases:

  • 5.1.1. According to the judgment of Step4, we can join the queue directly, add the task to runningAsyncCalls, and then allocate threads to execute the task through the thread pool. Execute () method in AsyncCall can execute the task.
  • 5.1.2 in AsyncCall the execute () method of getResponseWithInterceptorChain (), enter the interceptor chain process, and then to request, get the Response.
  • 5.1.3 If Response is normally received, run finished() to check whether any tasks need to be executed in the waiting queue.
  • 5.2.1. According to the judgment of Step4, we need to wait and cannot join the queue, so we call to join the readyAsyncCalls queue.
  • 5.2.2 When the Finished task is triggered, the dispatcher reassigns tasks in the waiting queue. If the finished task is idle, go to 5.1.1.

5. Summary of OKHTTP scheduling

  • Using Dispacher as scheduling, with the thread pool to achieve high concurrency, low blocking operation;
  • Deque is adopted as the collection, and first-in, first-out is adopted according to the order of joining the team.
  • The best part is calling the FINISHED function ina try/catch/finally to actively control the movement of the queue. Avoid using locks instead of wait/notify.