Okhttp中的WebSocket

项目需要使用WebSocket长连接来实现上报消息处理.看了看关于WebSocket源码梳理了一下
public void connect() {
    Request request = new Request.Builder().url(url).build();
    NotifyWebSocketListener listener = new NotifyWebSocketListener();
    //IApi.getOkHttp()这个方法是得到OkhttpClient的[所谓的OkhttpClient实例化]
    webSocket = IApi.getOkHttp().newWebSocket(request, listener);
}
//继承WebSocketListener 
private class NotifyWebSocketListener extends WebSocketListener {

    @Override
    public void onOpen(WebSocket webSocket, Response response) }

    @Override
    public void onMessage(WebSocket webSocket, String text) {
        MLog.i(TAG, "onMessage : " + text);
        //这里专门讲text消息放到MsgManager[消息处理类]中做专门处理
        if (null != MsgManager.getInstance()) {
            MsgManager.getInstance().dealAllMsg(text);
        }
    }

    @Override
    public void onMessage(WebSocket webSocket, ByteString bytes) {
        MLog.i(TAG, "onMessage bytes : " + bytes.hex());
        if (null != MsgManager.getInstance()) {
            MsgManager.getInstance().dealAllMsg(bytes);
        }
    }

    @Override
    public void onClosing(WebSocket webSocket, int code, String reason) {}

    @Override
    public void onClosed(WebSocket webSocket, int code, String reason) {}

    @Override
    public void onFailure(WebSocket webSocket, Throwable t, Response response) {}
}
重点在这里,打开OkHttpClient.class查找newWebSocket()方法:
/**
 * Uses {@code request} to connect a new web socket.使用{@code request}连接新的网络套接字。
 */
@Override 
public WebSocket newWebSocket(Request request, WebSocketListener listener) {
  RealWebSocket webSocket = new RealWebSocket(request, listener, new Random(), pingInterval);
  webSocket.connect(this);
  return webSocket;
}
//进入到webSocket.connect(this)中看一看
public void connect(OkHttpClient client) {
  //protocols(ONLY_HTTP1) 确认该列表具有我们需要的所有内容,并且没有禁止的内容。这里禁止内容就是"protocols must not contain http/1.0:和 null",能不能理解为WebSocket只支持http/1.1呢, 删除不再支持的协议。
  client = client.newBuilder()
      .eventListener(EventListener.NONE)
      .protocols(ONLY_HTTP1)
      .build();
  //对request对象的头部加工,Upgrade: websocketConnection: Upgrade这个就是Websocket的核心了,告诉 Apache、Nginx 等服务器:注意啦,我发起的是Websocket协议,快点帮我找到对应的助理处理。
Sec-WebSocket-Key是一个Base64 encode的值,这个是浏览器随机生成的,告诉服务器:我要验证你是不是真的是Websocket助理。
Sec-WebSocket-Version是告诉服务器所使用的 Websocket Draft(协议版本)
  final Request request = originalRequest.newBuilder()
      .header("Upgrade", "websocket")
      .header("Connection", "Upgrade")
      .header("Sec-WebSocket-Key", key)
      .header("Sec-WebSocket-Version", "13")
      .build();
   //从OkHttpClient中 获取WebSocket的call对象(回调使用)
  call = Internal.instance.newWebSocketCall(client, request);
//enqueue()方法是使用RealCall.class的enqueue()方法,这是一个入队的方法,而且是个异步的方法。这就说明webSocket建立连接后才响应回调。而且如果是长连接那么这个线程就一直在线程池里不会被释放掉。
  call.enqueue(new Callback() {
    @Override public void onResponse(Call call, Response response) {
      try {
        checkResponse(response);
      } catch (ProtocolException e) {
        failWebSocket(e, response);
        closeQuietly(response);
        return;
      }
      //将HTTP流提升为Web套接字流。
      StreamAllocation streamAllocation = Internal.instance.streamAllocation(call);
      streamAllocation.noNewStreams(); // Prevent connection pooling!
      Streams streams = streamAllocation.connection().newWebSocketStreams(streamAllocation);
      //处理所有网络套接字消息。
      try {
        listener.onOpen(RealWebSocket.this, response);
        String name = "OkHttp WebSocket " + request.url().redact();
        initReaderAndWriter(name, streams);
        streamAllocation.connection().socket().setSoTimeout(0);
        loopReader();//
      } catch (Exception e) {
        failWebSocket(e, null);
      }
    }

    @Override public void onFailure(Call call, IOException e) {
      failWebSocket(e, null);
    }
  });
}
//进入到enqueue()中看一看
@Override 
public void enqueue(Callback responseCallback) {
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  captureCallStackTrace();
  eventListener.callStart(this);
  //dispather() 调度
  client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
//Dispatcher(调度)类中的enqueue(AsyncCall call)方法
synchronized void enqueue(AsyncCall call) {
  if (runningAsyncCalls.size() < maxRequests[64] && runningCallsForHost(call) < maxRequestsPerHost[5]) {
    //runningAsyncCalls来记录在执行的Call,每次执行都会记录.
    runningAsyncCalls.add(call);
    //当向executor添加call的时候, 将任务放入SynchronousQueue中等待前面的request被取出才能执行之后的request,这里maxRequests 被定为64.超出64的将会被放入readyAsyncCalls。
    executorService().execute(call);
  } else {
    readyAsyncCalls.add(call);
  }
}
1:okhttp的websocket是异步的,并不会阻塞主线程,而且也不需要单独开辟一个子线程来创建连接。
2:会不会阻塞首先我们再次看看这个executorService的线程池结构。:首先 这个是dispatcher线程池的结构
public synchronized ExecutorService executorService() {
  if (executorService == null) {
    executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
        new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
  }
  return executorService;
}
SynchronousQueue是一个无缓存的阻塞的队列,什么意思呢?我们可以理解为当这个队列中有元素的时候,这个元素没有被取走(take方法)之前是不允许继续对之后的内容进行操作。
注意1:它一种阻塞队列,其中每个 put 必须等待一个 take,反之亦然。同步队列没有任何内部容量,甚至连一个队列的容量都没有。
注意2:它是线程安全的,是阻塞的。
注意3:不允许使用 null 元素。
注意4:公平排序策略是指调用put的线程之间,或take的线程之间。公平排序策略可以查考ArrayBlockingQueue中的公平策略。
所以这又解决了一个困扰我多年的难题:
okhttp的能同时执行多少个请求?
这个线程池的配置其实就是Executors提供的线程池配置方案之一,构造一个缓冲功能的线程池,配置corePoolSize=0,maximumPoolSize=Integer.MAX_VALUE,keepAliveTime=60s,以及一个无容量的阻塞队列 SynchronousQueue,因此任务提交之后,将会创建新的线程执行;线程空闲超过60s将会销毁:

 

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值