关于Https协议和HttpClient的实现详解

一、背景

HTTP是一个传输内容有可读性的公开协议,客户端与服务器端的数据完全通过明文传输。在这个背景之下,整个依赖于Http协议的互联网数据都是透明的,这带来了很大的数据安全隐患。想要解决这个问题有两个思路:

  • C/S端各自负责,即客户端与服务端使用协商好的加密内容在Http上通信
  • C/S端不负责加解密,加解密交给通信协议本身解决

第一种在现实中的应用范围其实比想象中的要广泛一些。双方线下交换密钥,客户端在发送的数据采用的已经是密文了,这个密文通过透明的Http协议在互联网上传输。服务端在接收到请求后,按照约定的方式解密获得明文。这种内容就算被劫持了也不要紧,因为第三方不知道他们的加解密方法。然而这种做法太特殊了,客户端与服务端都需要关心这个加解密特殊逻辑。

第二种C/S端可以不关心上面的特殊逻辑,他们认为发送与接收的都是明文,因为加解密这一部分已经被协议本身处理掉了。

从结果上看这两种方案似乎没有什么区别,但是从软件工程师的角度看区别非常巨大。因为第一种需要业务系统自己开发响应的加解密功能,并且线下要交互密钥,第二种没有开发量。

HTTPS是当前最流行的HTTP的安全形式,由NetScape公司首创。在HTTPS中,URL都是以https://开头,而不是http://。使用了HTTPS时,所有的HTTP的请求与响应在发送到网络上之前都进行了加密,这是通过在SSL层实现的。

二、加密方法

通过SSL层对明文数据进行加密,然后放到互联网上传输,这解决了HTTP协议原本的数据安全性问题。一般来说,对数据加密的方法分为对称加密与非对称加密。

2.1 对称加密

对称加密是指加密与解密使用同样的密钥,常见的算法有DES与AES等,算法时间与密钥长度相关。

对称密钥最大的缺点是需要维护大量的对称密钥,并且需要线下交换。加入一个网络中有n个实体,则需要n(n-1)个密钥。

2.2 非对称加密

非对称加密是指基于公私钥(public/private key)的加密方法,常见算法有RSA,一般而言加密速度慢于对称加密。

对称加密比非对称加密多了一个步骤,即要获得服务端公钥,而不是各自维护的密钥。

整个加密算法建立在一定的数论基础上运算,达到的效果是,加密结果不可逆。即只有通过私钥(private key)才能解密得到经由公钥(public key)加密的密文。

在这种算法下,整个网络中的密钥数量大大降低,每个人只需要维护一对公司钥即可。即n个实体的网络中,密钥个数是2n。

其缺点是运行速度慢。

2.3 混合加密

周星驰电影《食神》中有一个场景,黑社会火并,争论撒尿虾与牛丸的底盘划分问题。食神说:“真是麻烦,掺在一起做成撒尿牛丸那,笨蛋!”

对称加密的优点是速度快,缺点是需要交换密钥。非对称加密的优点是不需要交互密钥,缺点是速度慢。干脆掺在一起用好了。

混合加密正是HTTPS协议使用的加密方式。先通过非对称加密交换对称密钥,后通过对称密钥进行数据传输。

由于数据传输的量远远大于建立连接初期交换密钥时使用非对称加密的数据量,所以非对称加密带来的性能影响基本可以忽略,同时又提高了效率。

三、HTTPS握手

可以看到,在原HTTP协议的基础上,HTTPS加入了安全层处理:

  • 客户端与服务端交换证书并验证身份,现实中服务端很少验证客户端的证书
  • 协商加密协议的版本与算法,这里可能出现版本不匹配导致失败
  • 协商对称密钥,这个过程使用非对称加密进行
  • 将HTTP发送的明文使用3中的密钥,2中的加密算法加密得到密文
  • TCP层正常传输,对HTTPS无感知

四、HttpClient对HTTPS协议的支持

4.1 获得SSL连接工厂以及域名校验器

作为一名软件工程师,我们关心的是“HTTPS协议”在代码上是怎么实现的呢?探索HttpClient源码的奥秘,一切都要从HttpClientBuilder开始。

public CloseableHttpClient build() {
 //省略部分代码
 HttpClientConnectionManager connManagerCopy = this.connManager;
 //如果指定了连接池管理器则使用指定的,否则新建一个默认的
 if (connManagerCopy == null) {
  LayeredConnectionSocketFactory sslSocketFactoryCopy = this.sslSocketFactory;
  if (sslSocketFactoryCopy == null) {
  //如果开启了使用环境变量,https版本与密码控件从环境变量中读取
  final String[] supportedProtocols = systemProperties ? split(
   System.getProperty("https.protocols")) : null;
  final String[] supportedCipherSuites = systemProperties ? split(
   System.getProperty("https.cipherSuites")) : null;
  //如果没有指定,使用默认的域名验证器,会根据ssl会话中服务端返回的证书来验证与域名是否匹配
  HostnameVerifier hostnameVerifierCopy = this.hostnameVerifier;
  if (hostnameVerifierCopy == null) {
   hostnameVerifierCopy = new DefaultHostnameVerifier(publicSuffixMatcherCopy);
  }
  //如果制定了SslContext则生成定制的SSL连接工厂,否则使用默认的连接工厂
  if (sslContext != null) {
   sslSocketFactoryCopy = new SSLConnectionSocketFactory(
    sslContext, supportedProtocols, supportedCipherSuites, hostnameVerifierCopy);
  } else {
   if (systemProperties) {
   sslSocketFactoryCopy = new SSLConnectionSocketFactory(
    (SSLSocketFactory) SSLSocketFactory.getDefault(),
    supportedProtocols, supportedCipherSuites, hostnameVerifierCopy);
   } else {
   sslSocketFactoryCopy = new SSLConnectionSocketFactory(
    SSLContexts.createDefault(),
    hostnameVerifierCopy);
   }
  }
  }
  //将Ssl连接工厂注册到连接池管理器中,当需要产生Https连接的时候,会根据上面的SSL连接工厂生产SSL连接
  @SuppressWarnings("resource")
  final PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager(
   RegistryBuilder.<ConnectionSocketFactory>create()
   .register("http", PlainConnectionSocketFactory.getSocketFactory())
   .register("https", sslSocketFactoryCopy)
   .build(),
   null,
   null,
   dnsResolver,
   connTimeToLive,
   connTimeToLiveTimeUnit != null ? connTimeToLiveTimeUnit : TimeUnit.MILLISECONDS);
  //省略部分代码
 }
}

上面的代码将一个Ssl连接工厂SSLConnectionSocketFactory创建,并注册到了连接池管理器中,供之后生产Ssl连接使用。连接池的问题参考://www.jb51.net/article/141015.htm

这里在配置SSLConnectionSocketFactory时用到了几个关键的组件,域名验证器HostnameVerifier以及上下文SSLContext。

其中HostnameVerifier用来验证服务端证书与域名是否匹配,有多种实现,DefaultHostnameVerifier采用的是默认的校验规则,替代了之前版本中的BrowserCompatHostnameVerifier与StrictHostnameVerifier。NoopHostnameVerifier替代了AllowAllHostnameVerifier,采用的是不验证域名的策略。

注意,这里有一些区别,BrowserCompatHostnameVerifier可以匹配多级子域名,"*.foo.com"可以匹配"a.b.foo.com"。StrictHostnameVerifier不能匹配多级子域名,只能到"a.foo.com"。

而4.4之后的HttpClient使用了新的DefaultHostnameVerifier替换了上面的两种策略,只保留了一种严格策略及StrictHostnameVerifier。因为严格策略是IE6与JDK本身的策略,非严格策略是curl与firefox的策略。即默认的HttpClient实现是不支持多级子域名匹配策略的。

SSLContext存放的是和密钥有关的关键信息,这部分与业务直接相关,非常重要,这个放在后面单独分析。

4.2 如何获得SSL连接

如何从连接池中获得一个连接,这个过程之前的文章中有分析过,这里不做分析,参考连接://www.jb51.net/article/141015.htm。

在从连接池中获得一个连接后,如果这个连接不处于establish状态,就需要先建立连接。

DefaultHttpClientConnectionOperator部分的代码为:

public void connect(
   final ManagedHttpClientConnection conn,
   final HttpHost host,
   final InetSocketAddress localAddress,
   final int connectTimeout,
   final SocketConfig socketConfig,
   final HttpContext context) throws IOException {
  //之前在HttpClientBuilder中register了http与https不同的连接池实现,这里lookup获得Https的实现,即SSLConnectionSocketFactory
  final Lookup<ConnectionSocketFactory> registry = getSocketFactoryRegistry(context);
  final ConnectionSocketFactory sf = registry.lookup(host.getSchemeName());
  if (sf == null) {
   throw new UnsupportedSchemeException(host.getSchemeName() +
     " protocol is not supported");
  }
  //如果是ip形式的地址可以直接使用,否则使用dns解析器解析得到域名对应的ip
  final InetAddress[] addresses = host.getAddress() != null ?
    new InetAddress[] { host.getAddress() } : this.dnsResolver.resolve(host.getHostName());
  final int port = this.schemePortResolver.resolve(host);
  //一个域名可能对应多个Ip,按照顺序尝试连接
  for (int i = 0; i < addresses.length; i++) {
   final InetAddress address = addresses[i];
   final boolean last = i == addresses.length - 1;
   //这里只是生成一个socket,还并没有连接
   Socket sock = sf.createSocket(context);
   //设置一些tcp层的参数
   sock.setSoTimeout(socketConfig.getSoTimeout());
   sock.setReuseAddress(socketConfig.isSoReuseAddress());
   sock.setTcpNoDelay(socketConfig.isTcpNoDelay());
   sock.setKeepAlive(socketConfig.isSoKeepAlive());
   if (socketConfig.getRcvBufSize() > 0) {
    sock.setReceiveBufferSize(socketConfig.getRcvBufSize());
   }
   if (socketConfig.getSndBufSize() > 0) {
    sock.setSendBufferSize(socketConfig.getSndBufSize());
   }

   final int linger = socketConfig.getSoLinger();
   if (linger >= 0) {
    sock.setSoLinger(true, linger);
   }
   conn.bind(sock);

   final InetSocketAddress remoteAddress = new InetSocketAddress(address, port);
   if (this.log.isDebugEnabled()) {
    this.log.debug("Connecting to " + remoteAddress);
   }
   try {
    //通过SSLConnectionSocketFactory建立连接并绑定到conn上
    sock = sf.connectSocket(
      connectTimeout, sock, host, remoteAddress, localAddress, context);
    conn.bind(sock);
    if (this.log.isDebugEnabled()) {
     this.log.debug("Connection established " + conn);
    }
    return;
   }
   //省略一些代码
  }
 }

在上面的代码中,我们看到了是建立SSL连接之前的准备工作,这是通用流程,普通HTTP连接也一样。SSL连接的特殊流程体现在哪里呢?

SSLConnectionSocketFactory部分源码如下:

@Override
 public Socket connectSocket(
   final int connectTimeout,
   final Socket socket,
   final HttpHost host,
   final InetSocketAddress remoteAddress,
   final InetSocketAddress localAddress,
   final HttpContext context) throws IOException {
  Args.notNull(host, "HTTP host");
  Args.notNull(remoteAddress, "Remote address");
  final Socket sock = socket != null ? socket : createSocket(context);
  if (localAddress != null) {
   sock.bind(localAddress);
  }
  try {
   if (connectTimeout > 0 && sock.getSoTimeout() == 0) {
    sock.setSoTimeout(connectTimeout);
   }
   if (this.log.isDebugEnabled()) {
    this.log.debug("Connecting socket to " + remoteAddress + " with timeout " + connectTimeout);
   }
   //建立连接
   sock.connect(remoteAddress, connectTimeout);
  } catch (final IOException ex) {
   try {
    sock.close();
   } catch (final IOException ignore) {
   }
   throw ex;
  }
  // 如果当前是SslSocket则进行SSL握手与域名校验
  if (sock instanceof SSLSocket) {
   final SSLSocket sslsock = (SSLSocket) sock;
   this.log.debug("Starting handshake");
   sslsock.startHandshake();
   verifyHostname(sslsock, host.getHostName());
   return sock;
  } else {
   //如果不是SslSocket则将其包装为SslSocket
   return createLayeredSocket(sock, host.getHostName(), remoteAddress.getPort(), context);
  }
 }

 @Override
 public Socket createLayeredSocket(
   final Socket socket,
   final String target,
   final int port,
   final HttpContext context) throws IOException {
   //将普通socket包装为SslSocket,socketfactory是根据HttpClientBuilder中的SSLContext生成的,其中包含密钥信息
  final SSLSocket sslsock = (SSLSocket) this.socketfactory.createSocket(
    socket,
    target,
    port,
    true);
  //如果制定了SSL层协议版本与加密算法,则使用指定的,否则使用默认的
  if (supportedProtocols != null) {
   sslsock.setEnabledProtocols(supportedProtocols);
  } else {
   // If supported protocols are not explicitly set, remove all SSL protocol versions
   final String[] allProtocols = sslsock.getEnabledProtocols();
   final List<String> enabledProtocols = new ArrayList<String>(allProtocols.length);
   for (final String protocol: allProtocols) {
    if (!protocol.startsWith("SSL")) {
     enabledProtocols.add(protocol);
    }
   }
   if (!enabledProtocols.isEmpty()) {
    sslsock.setEnabledProtocols(enabledProtocols.toArray(new String[enabledProtocols.size()]));
   }
  }
  if (supportedCipherSuites != null) {
   sslsock.setEnabledCipherSuites(supportedCipherSuites);
  }

  if (this.log.isDebugEnabled()) {
   this.log.debug("Enabled protocols: " + Arrays.asList(sslsock.getEnabledProtocols()));
   this.log.debug("Enabled cipher suites:" + Arrays.asList(sslsock.getEnabledCipherSuites()));
  }

  prepareSocket(sslsock);
  this.log.debug("Starting handshake");
  //Ssl连接握手
  sslsock.startHandshake();
  //握手成功后校验返回的证书与域名是否一致
  verifyHostname(sslsock, target);
  return sslsock;
 }

可以看到,对于一个SSL通信而言。首先是建立普通socket连接,然后进行ssl握手,之后验证证书与域名一致性。之后的操作就是通过SSLSocketImpl进行通信,协议细节在SSLSocketImpl类中体现,但这部分代码jdk并没有开源,感兴趣的可以下载相应的openJdk源码继续分析。

五、本文总结

  1. https协议是http的安全版本,做到了传输层数据的安全,但对服务器cpu有额外消耗
  2. https协议在协商密钥的时候使用非对称加密,密钥协商结束后使用对称加密
  3. 有些场景下,即使通过了https进行了加解密,业务系统也会对报文进行二次加密与签名
  4. HttpClient在build的时候,连接池管理器注册了两个SslSocketFactory,用来匹配http或者https字符串
  5. https对应的socket建立原则是先建立,后验证域名与证书一致性
  6. ssl层加解密由jdk自身完成,不需要httpClient进行额外操作

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • HTTP协议入门_动力节点Java学院整理

    HTTP 协议是互联网的基础协议,也是网页开发的必备知识,最新版本 HTTP/2 更是让它成为技术热点. 本文介绍 HTTP 协议的历史演变和设计思路. 一.HTTP/0.9 HTTP 是基于 TCP/IP 协议的应用层协议.它不涉及数据包(packet)传输,主要规定了客户端和服务器之间的通信格式,默认使用80端口. 最早版本是1991年发布的0.9版.该版本极其简单,只有一个命令GET. GET /index.html 上面命令表示,TCP 连接(connection)建立后,客户端向服务器

  • Java与Http协议的详细介绍

    Java与Http协议的详细介绍 引言      http(超文本传输协议)是一个基于请求与响应模式的.无状态的.应用层的协议,常基于TCP的连接方式.HTTP协议的主要特点是:      1.支持客户/服务器模式.      2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径.由于HTTP协议简单,通信速度很快.      3.灵活:HTTP允许传输任意类型的数据对象.类型由Content-Type加以标记.      4.无连接:即每次连接只处理一个请求,处理完客户的请求,并收到客

  • http协议详解(超详细)

    http协议学习系列             1. 基础概念篇 1.1 介绍 HTTP是Hyper Text Transfer Protocol(超文本传输协议)的缩写.它的发展是万维网协会(World Wide Web Consortium)和Internet工作小组IETF(Internet Engineering Task Force)合作的结果,(他们)最终发布了一系列的RFC,RFC 1945定义了HTTP/1.0版本.其中最著名的就是RFC 2616.RFC 2616定义了今天普遍使

  • 基于HTTP协议的一些实时数据获取技术详解

    HTTP协议 HTTP协议大家都很熟悉了,开始本文之前,首先简单回顾一下HTTP协议. HTTP协议是建立在TCP协议上的应用层协议,协议的本质是请求----应答: 即对于HTTP协议来说,服务端给一次响应后整个请求就结束了,这是HTTP请求最大的特点,也是由于这个特点,HTTP请求无法做到的是服务端向客户端主动推送数据. 但由于HTTP协议的广泛应用,很多时候确实又想使用HTTP协议去实现实时的数据获取,这种时候应当怎么办呢?下面首先介绍几种基于HTTP协议的实时数据获取方法. 短轮询 轮询是

  • 详解HTTP协议(很经典)

    引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展.目前在WWW中使用的是HTTP/1.0的第六版,HTTP/1.1的规范化工作正在进行之中,而且HTTP-NG(Next Generation of HTTP)的建议已经提出. HTTP协议的主要特点可概括如下: 1.支持客户/服务器模式. 2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径.请求方法常用的有GET.HEAD.

  • HTTP协议详解_动力节点Java学院整理

    一.概念 协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则,超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器. HTTP协议,即超文本传输协议(Hypertext transfer protocol).是一种详细规定了浏览器和万维网(WWW = World Wide Web)服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议. HTTP协议是用于从WWW服务器传输超文本到本地浏览器的传送协议.

  • HTTP协议简介_动力节点Java学院整理

    TCP协议对应于传输层,而HTTP协议对应于应用层,从本质上来说,二者没有可比性.Http协议是建立在TCP协议基础之上的,当浏览器需要从服务器获取网页数据的时候,会发出一次Http请求.Http会通过TCP建立起一个到服务器的连接通道,当本次请求需要的数据完毕后,Http会立即将TCP连接断开,这个过程是很短的.所以Http连接是一种短连接,是一种无状态的连接.所谓的无状态,是指浏览器每次向服务器发起请求的时候,不是通过一个连接,而是每次都建立一个新的连接.如果是一个连接的话,服务器进程中就能

  • 网络传输协议(http协议)

    概述:指服务器和客户端间进行通信时的约束和规范,客户端与服务端的数据交互并不是杂乱无章的,需要遵照(基于)一定的规范进行 常见的协议: a) HTTP.HTTPS 超文本传输协议 b) FTP 文件传输协议 c) SMTP 简单邮件传输协议 本文主要介绍http超文本传输协议. 1.HTTP协议 即超文本传输协议,网站是基于HTTP协议的,例如网站的图片.CSS.JS等都是基于HTTP协议进行传输的.HTTP协议是由从客户机到服务器的请求(Request)和从服务器到客户机的响应(Respons

  • 详解HTTP协议简介

    一.简介 HTTP(HyperText Transfer Protocol, 超文本传输协议) 是访问互联网使用的核心通信协议,也是所有web应用程序使用的通信协议. 消息模型:客户端发送请求消息,服务器返回响应消息.传输层使用具有状态的TCP协议,但HTTP协议本身不具有状态. 二.HTTP请求 HTTP请求消息分为消息头和消息主体(可选),消息头和消息主体用空白行分隔.实例: GET / HTTP/1.1 Host: www.cnbeta.com User-Agent: Mozilla/5.

  • 关于Https协议和HttpClient的实现详解

    一.背景 HTTP是一个传输内容有可读性的公开协议,客户端与服务器端的数据完全通过明文传输.在这个背景之下,整个依赖于Http协议的互联网数据都是透明的,这带来了很大的数据安全隐患.想要解决这个问题有两个思路: C/S端各自负责,即客户端与服务端使用协商好的加密内容在Http上通信 C/S端不负责加解密,加解密交给通信协议本身解决 第一种在现实中的应用范围其实比想象中的要广泛一些.双方线下交换密钥,客户端在发送的数据采用的已经是密文了,这个密文通过透明的Http协议在互联网上传输.服务端在接收到

  • Java服务调用RestTemplate与HttpClient的使用详解

    目录 概述 RestTemplate 概述及依赖 配置类 使用 GET请求 POST请求 上传文件 HttpClient 概述 使用 概述 常见的远程调用方式有以下2种: RPC: Remote Produce Call远程过程调用,类似的还有RMI(remote method invoke).自定义数据格式,基于原生TCP通信,速度快,效率高.早期的webservice,现在热门的dubbo,都是RPC的典型代表. Http: http其实是一种网络传输协议,基于TCP,规定了数据传输的格式.

  • IOS开发 支持https请求以及ssl证书配置详解

    IOS开发 支持https请求以及ssl证书配置详解 前言: 众所周知,苹果有言,从2017年开始,将屏蔽http的资源,强推https 楼主正好近日将http转为https,给还没动手的朋友分享一二 一.证书准备 1.证书转换 在服务器人员,给你发送的crt证书后,进到证书路径,执行下面语句 // openssl x509 -in 你的证书.crt -out 你的证书.cer -outform der 这样你就可以得到cer类型的证书了.双击,导入电脑. 2.证书放入工程 1.可以直接把转换好

  • Python并发编程协程(Coroutine)之Gevent详解

    Gevent官网文档地址:http://www.gevent.org/contents.html 基本概念 我们通常所说的协程Coroutine其实是corporateroutine的缩写,直接翻译为协同的例程,一般我们都简称为协程. 在linux系统中,线程就是轻量级的进程,而我们通常也把协程称为轻量级的线程即微线程. 进程和协程 下面对比一下进程和协程的相同点和不同点: 相同点: 我们都可以把他们看做是一种执行流,执行流可以挂起,并且后面可以在你挂起的地方恢复执行,这实际上都可以看做是con

  • iOS开发实现HTTPS之cer文件的使用详解

    iOS开发中实现支持HTTPS,有两种方法:一是后台那边都处理好了,移动端直接可以使用HTTPS接口,二是后台给移动端一个服务器证书cer 文件,这时我们就需要将cer文件导入到我们的工程中,以下是实现方法 1. 双击证书,这时证书已经添加到了钥匙串中 2. 将cer 文件拖入工程中 3. 如果使用的是AFNetwotking 的话,在代码中添加以下代码 AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; //证书 AF

  • 对python3标准库httpclient的使用详解

    如下所示: import http.client, urllib.parse import http.client, urllib.parse import random USER_AGENTS = [ "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)", "Mozilla/4.0 (compatible; M

  • Java原生HttpClient的使用详解

    目录 1.信任证书管理类 2.HttpClient类 3.发送请求工具类 4.测试 提到Java发送HTTP请求,大家首先想到的是用apache的HttpClient,或者squareup的OkHttp.而在Java11之前,原生Java对此的支持还是比较差的,虽然可以HttpURLConnection.URLConnection.Socket等自带的类发送请求,但是操作比较复杂.直到Java11发布,Java本身也自带了HttpClient.自2020年初,我就在开发中广泛使用了这一新特性,感

  • Kotlin协程Dispatchers原理示例详解

    目录 前置知识 demo startCoroutineCancellable intercepted()函数 DefaultScheduler中找dispatch函数 Runnable传入 Worker线程执行逻辑 小结 前置知识 Kotlin协程不是什么空中阁楼,Kotlin源代码会被编译成class字节码文件,最终会运行到虚拟机中.所以从本质上讲,Kotlin和Java是类似的,都是可以编译产生class的语言,但最终还是会受到虚拟机的限制,它们的代码最终会在虚拟机上的某个线程上被执行. 之

  • Golang控制协程执行顺序方法详解

    目录 循环控制 通道控制 互斥锁 async.Mutex 在 Go 里面的协程执行实际上默认是没有严格的先后顺序的.由于 Go 语言 GPM 模型的设计理念,真正执行实际工作的实际上是 GPM 中的 M(machine) 执行器,而我们的协程任务 G(goroutine) 协程需要被 P(produce) 关联到某个 M 上才能被执行.而每一个 P 都有一个私有队列,除此之外所有的 P 还共用一个公共队列.因此当我们创建了一个协程之后,并不是立即执行,而是进入队列等待被分配,且不同队列之间没有顺

  • PHP7下协程的实现方法详解

    前言 相信大家都听说过『协程』这个概念吧. 但是有些同学对这个概念似懂非懂,不知道怎么实现,怎么用,用在哪,甚至有些人认为yield就是协程! 我始终相信,如果你无法准确地表达出一个知识点的话,我可以认为你就是不懂. 如果你之前了解过利用PHP实现协程的话,你肯定看过鸟哥的那篇文章:在PHP中使用协程实现多任务调度| 风雪之隅 鸟哥这篇文章是从国外的作者翻译来的,翻译的简洁明了,也给出了具体的例子了. 我写这篇文章的目的,是想对鸟哥文章做更加充足的补充,毕竟有部分同学的基础还是不够好,看得也是云

随机推荐