项目需要使用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: websocket与Connection: 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将会销毁: